useEffect 후크 내부에 상태를 설정할 수 있습니까?


124

다른 상태에 의존하는 상태가 있다고 가정 해 보겠습니다 (예 : A가 변경되면 B가 변경되기를 원합니다).

A를 관찰하고 useEffect 후크 내부에 B를 설정하는 후크를 만드는 것이 적절합니까?

버튼을 클릭하면 첫 번째 효과가 발생하여 다음 렌더링 전에 b가 변경되어 두 번째 효과가 발생하도록 효과가 계단식으로 표시됩니까? 이와 같은 코드를 구조화하는 데 성능 저하가 있습니까?

let MyComponent = props => {
  let [a, setA] = useState(1)
  let [b, setB] = useState(2)
  useEffect(
    () => {
      if (/*some stuff is true*/) {
        setB(3)
      }
    },
    [a],
  )
  useEffect(
    () => {
      // do some stuff
    },
    [b],
  )

  return (
    <button
      onClick={() => {
        setA(5)
      }}
    >
      click me
    </button>
  )
}

답변:


31

효과는 항상 렌더링 단계가 완료된 후에 실행됩니다. 한 효과 내에서 State를 설정하더라도 다른 효과는 업데이트 된 상태를 읽고 렌더링 단계 후에 만 ​​작업을 수행합니다.

동일한 논리를 실행하려는 경우 b이외에 다른 이유로 인해 변경 될 수 있는 가능성이없는 한 동일한 효과로 두 작업을 모두 수행하는 것이 더 좋습니다.changing a


4
따라서 A가 B를 변경하면 구성 요소가 두 번 렌더링됩니까?
Dan Ruswick

2
나는 또한 질문 위의 답 알고 싶다
alaboudi

2
예 @alaboudi, A는 다음 구성 요소가 두 번 렌더링 않는 B를 설정 실행에 useeffect 원인 변경하는 경우
하기 Shubham 카트리

@alaboudi 예 .. Shubham Khatri가 다시 렌더링 할 것이라고 말했듯이. 하지만 당신은 참조하는 두 번째 인수를 사용하여 재 렌더링 후 이펙트를 호출 건너 뛸 수 있습니다 reactjs.org/docs/...
Karthikeyan

108

일반적으로 setState내부 useEffect를 사용하면 원하지 않는 무한 루프가 생성됩니다. 나중에 다루게 될 규칙에는 몇 가지 예외가 있습니다.

useEffect는 각 렌더링 후 호출되고 setState내부에서 사용되면 구성 요소가 다시 렌더링되어 호출 useEffect등을 수행합니다.

useStateinside of 를 사용 useEffect하면 무한 루프가 발생하지 않는 인기있는 경우 중 하나는 useEffectlike에 대한 두 번째 인수로 빈 배열을 전달할 때 useEffect(() => {....}, [])입니다. 즉, 효과 함수는 첫 번째 마운트 / 렌더링 이후에만 한 번 호출되어야합니다. 구성 요소에서 데이터 가져 오기를 수행하고 요청 데이터를 구성 요소의 상태로 저장하려는 경우 널리 사용됩니다.


3
setState내부 에서 사용하는 또 다른 경우 useEffectsetting state구독 또는 이벤트 리스너 내부 입니다 . 그러나 구독 취소하는 것을 잊지 마세요 reactjs.org/docs/hooks-effect.html#effects-with-cleanup
timqian

35
이것은 엄격하게 사실이 아닙니다. useState는 상태를 업데이트하는 값이 이전 값과 다른 경우에만 발생하므로 값이주기간에 변경되지 않는 한 무한 루프가 방지됩니다.
RobM

14
이 답변은 정확하지 않으며 질문의 요점이 아닙니다. 코드에서 버튼을 클릭 할 때 구성 요소가 두 번만 렌더링되고 무한 루프가 없습니다
Bogdan D

15
useEffect 내부에 상태를 설정하는 것은 매우 일반적인 사용 사례입니다. 데이터 로딩, useEffect 호출 API, 데이터 가져 오기, useState의 세트 부분 사용에 대해 생각해보십시오.
badbod99

3
귀하가 언급 한 문제를 해결하기 위해 답변을 업데이트했습니다. 이제 더 나은가요?
Hossam Mourad 19

58

향후 목적을 위해 다음도 도움이 될 수 있습니다.

useEffect이미 설명한대로 루프를 생성하지 않도록주의를 기울여야 하는 경우 setState를 사용 하는 것이 좋습니다.

그러나 이것이 발생할 수있는 유일한 문제는 아닙니다. 아래를 참조하십시오.

부모로부터 Comp받는 구성 요소 가 props있고 의 상태 props를 설정하려는 변경 에 따라 있다고 상상해보십시오 Comp. 어떤 이유로 각 소품마다 다른 변경해야합니다 useEffect.

하지 마십시오

useEffect(() => {
  setState({ ...state, a: props.a });
}, [props.a]);

useEffect(() => {
  setState({ ...state, b: props.b });
}, [props.b]);

이 예에서 볼 수 있듯이 https://codesandbox.io/s/confident-lederberg-dtx7w 에서 볼 수 있듯이 상태를 변경하지 않을 수 있습니다.

때문에이 예에서 일어나는 이유는 그건 모두 useEffects이 같은 실행주기를 반응 은 모두 변경할 때 prop.aprop.b의 가치, 그래서 {...state}당신이 할 때이 setState정확히 모두에서 동일 useEffect는 같은 맥락에서 때문이다. 두 번째를 실행 setState하면 첫 번째setState .

이 대신 수행

이 문제에 대한 해결책은 기본적으로 다음 setState과 같이 호출하는 것입니다.

useEffect(() => {
  setState(state => ({ ...state, a: props.a }));
}, [props.a]);

useEffect(() => {
  setState(state => ({ ...state, b: props.b }));
}, [props.b]);

여기에서 솔루션을 확인하십시오 : https://codesandbox.io/s/mutable-surf-nynlx

이제 setState.

나는 이것이 누군가에게 도움이되기를 바랍니다!


3
위의 솔루션은 나에게 도움이setName(name => ({ ...name, a: props.a }));
mufaddal_mw

2
이것은 화살표 기능 부분에서도 도움이되었습니다setItems(items => [...items, item])
Stefan Zhelyazkov

와, 당신은 대단해요. 오늘 내 a * s를 구했습니다.
Pratik Soni

해결책없이 오전 7 시부 터 오후 3 시까 지 보냈고 이제 당신은 나를 구했습니다.
Dinindu Kanchana

24

useEffect특정 소품이나 상태에 연결할 수 있습니다. 따라서 무한 루프 훅을 피하기 위해해야 ​​할 일은 어떤 변수 나 상태를 바인딩하는 것입니다.

예를 들면 :

useEffect(myeffectCallback, [])

위의 효과는 구성 요소가 렌더링 된 후에 만 ​​발생합니다. 이것은 componentDidMount수명주기 와 유사합니다.

const [something, setSomething] = withState(0)
const [myState, setMyState] = withState(0)
useEffect(() => {
  setSomething(0)
}, myState)

위의 효과는 내 상태가 변경된 경우에만 componentDidUpdate발생합니다. 이것은 모든 변경 상태가 발생하는 것은 아니라는 점 을 제외하고 는 비슷 합니다.

링크를 통해 자세한 내용을 읽을 수 있습니다.


1
감사합니다.이 답변은 다른 답변이하지 않은 방식으로 useEffect의 종속성 배열을 해결합니다. 빈 배열을 useEffect의 두 번째 인수로 포함하면 구성 요소가 렌더링 된 후 useEffect가 실행되지만 특정 상태 또는 특정 상태의 배열을 포함하면 참조의 상태가 변경 될 때 useEffect가 실행됩니다.
adriaanbd 20.10.20

11

▶ 1. useEffect 후크 내부에 상태를 설정할 수 있나요?

원칙적으로 내부 useEffect렌더링 중을 포함하여 필요한 곳에 상태를 자유롭게 설정할 수 있습니다 . 후크를 deps적절하게 설정하거나 조건부로 상태 를 설정하여 무한 루프를 피하십시오 .


▶ 2. 다른 상태에 의존하는 상태가 있다고 가정 해 보겠습니다. A를 관찰하고 useEffect 후크 내부에 B를 설정하는 후크를 만드는 것이 적절합니까?

다음에 대한 고전적인 사용 사례를 설명 했습니다 useReducer.

useReducer일반적으로 여러 하위 값 을 포함 하는 복잡한 상태 논리가 있거나 다음 상태가 이전 상태에 의존 하는 useState경우 보다 선호됩니다 . ( React 문서 )

상태 변수 설정 이 다른 상태 변수 의 현재 값에 따라 달라지는 경우 둘 다로 대체 할 수 있습니다 . [...] 글을 쓰는 자신을 발견하면 대신 감속기를 사용하는 것을 고려하는 것이 좋습니다. (useReducer setSomething(something => ...) Dan Abramov, Overreacted 블로그 )


▶ 3. 버튼을 클릭하면 첫 번째 효과가 실행되어 다음 렌더링 전에 b가 변경되어 두 번째 효과가 실행되도록 효과가 계단식으로 표시됩니까?

useEffect항상 렌더링이 커밋되고 DOM 변경 사항이 적용된 후에 실행 됩니다. 첫 번째 효과가 발생하고 변경 b되고 다시 렌더링됩니다. 이 렌더가 완료된 후 두 번째 효과는b 변경 사항 됩니다.


▶ 4. 이와 같이 코드를 구조화하면 성능상의 단점이 있습니까?

예. 상태 변경을 래핑하여 b분리에 useEffect대한 a이러한 영향은 잠재적으로 사용자가 볼 수있다 - 브라우저는 추가적인 레이아웃 / 페인트 위상을 갖는다. useReducer시도해 보고 싶은 방법이 없다면 직접 b상태를 변경할 수 있습니다 a.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.