반응 기능 구성 요소에서 setState의 기능 구문을 사용하는 것은 무엇입니까? [복제]

Dec 13 2020

우리는 기능적 구성 요소에 대해 이야기하고 있습니다 useState

의 말을하자

const [age, setAge] = useState(0)

이제 업데이트하는 동안 age이전을 사용해야합니다.age

React 문서 는 함수를 전달할 수있는 FUNCTIONAL UPDATES 라는 것을 언급하고 그에 대한 인수는 상태의 이전 값이 될 것입니다.

setState((previousAge) => previousAge + 1)

그냥 할 수 있는데 왜 이렇게해야하나요

setState(previousAge + 1)

기능 사용의 이점은 무엇인가 setState,

클래스 기반 구성 요소에는 기능적 방식으로 상태 업데이트 일괄 처리 라는 것이 있다는 것을 알고 있지만 기능 구성 요소 문서에서는 이와 같은 것을 찾을 수 없습니다.

답변

2 ehab Dec 14 2020 at 01:38

업데이트가 상태에서 발견 된 이전 값에 따라 달라지는 경우에는 동일하지 않은 경우 기능적 형식을 사용해야합니다. 이 경우 함수형을 사용하지 않으면 언젠가 코드가 깨질 것입니다.

왜 깨지고 언제

React 기능적 구성 요소는 단지 클로저 일뿐입니다. 클로저에있는 상태 값이 구식 일 수 있습니다. 이것은 클로저 내부의 값이 해당 구성 요소에 대한 React 상태의 값과 일치하지 않는다는 것을 의미합니다. 다음과 같은 경우 :

1- 비동기 작업 ( 이 예제에서는 느린 추가를 클릭 한 다음 추가 버튼을 여러 번 클릭하면 나중에 느린 추가 버튼을 클릭했을 때 상태가 클로저 내부의 상태로 재설정되었음을 알 수 있습니다)

const App = () => {
  const [counter, setCounter] = useState(0);

  return (
    <>
      <p>counter {counter} </p>
      <button
        onClick={() => {
          setCounter(counter + 1);
        }}
      >
        immediately add
      </button>
      <button
        onClick={() => {
          setTimeout(() => setCounter(counter + 1), 1000);
        }}
      >
        Add
      </button>
    </>
  );
};

2- 동일한 클로저에서 업데이트 함수를 여러 번 호출 할 때

const App = () => {
  const [counter, setCounter] = useState(0);

  return (
    <>
      <p>counter {counter} </p>
      <button
        onClick={() => {
          setCounter(counter + 1);
          setCounter(counter + 1);
        }}
      >
        Add twice
      </button>
   
    </>
  );
}
1 HeroWanders Dec 13 2020 at 23:59

setter가 얼마나 빨리 / 자주 호출되는지에 따라 문제가 발생할 수 있습니다.

클로저에서 값을 가져 오는 간단한 방법을 사용하는 경우 두 렌더링 간의 후속 호출이 원하는 효과를 얻지 못할 수 있습니다.

간단한 예 :

function App() {
    const [counter, setCounter] = useState(0);
    const incWithClosure = () => {
        setCounter(counter + 1);
    };
    const incWithUpdate = () => {
        setCounter(oldCounter => oldCounter + 1);
    };

    return (<>
        <button onClick={_ => { incWithClosure(); incWithClosure(); }}>
            Increment twice using incWithClosure
        </button>
        <button onClick={_ => { incWithUpdate(); incWithUpdate(); }}>
            Increment twice using incWithUpdate
        </button>
        <p>{counter}</p>
    </>);
}

두 버튼 모두 증분 메서드 중 하나를 두 번 호출합니다. 그러나 우리는 다음을 관찰합니다.

  • 첫 번째 버튼은 카운터를 1 씩만 증가시킵니다.
  • 두 번째 버튼은 카운터를 2 씩 증가시킬 것이며 이는 아마도 원하는 결과 일 것입니다.

언제 이런 일이 일어날 수 있습니까?

  • 당연히, incWithClosure서로 즉시 여러 번 호출 되면
  • 비동기 작업이 관련되면 쉽게 발생할 수 있습니다 (아래 참조).
  • 아마도 React가 할 일이 많으면 스케줄링 알고리즘이 동일한 이벤트 핸들러를 사용하여 여러 번의 매우 빠른 클릭을 처리하도록 결정할 수 있습니다.

비동기 작업의 예 (리소스로드 시뮬레이션) :

function App() {
  const [counter, setCounter] = useState(0);
  const incWithClosureDelayed = () => {
    setTimeout(() => {
      setCounter(counter + 1);
    }, 1000);
  };
  const incWithUpdateDelayed = () => {
    setTimeout(() => {
      setCounter((oldCounter) => oldCounter + 1);
    }, 1000);
  };

  return (
    <>
      <button onClick={(_) => incWithClosureDelayed()}>
        Increment slowly using incWithClosure
      </button>
      <button onClick={(_) => incWithUpdateDelayed()}>
        Increment slowly using incWithUpdate
      </button>
      <p>{counter}</p>
    </>
  );
}

첫 번째 버튼을 두 번 (1 초 이내) 클릭하고 카운터가 1만큼만 증가하는지 확인합니다. 두 번째 버튼은 올바른 동작을합니다.

slebetman Dec 13 2020 at 23:26

당신이하지 않으면 때문에 것이다 당신을위한 이전 값을 얻을 어떤 점에서 찾을 수 있습니다 age. 문제는 때때로 당신이 제안한 것이 효과가 있다는 것입니다. 그러나 때로는 그렇지 않습니다. 현재 현재 코드에서 손상되지 않을 수 있지만 몇 주 전에 작성한 다른 코드 또는 지금부터 몇 달 후 현재 코드에서 손상 될 수 있습니다.

증상은 정말, 정말 이상합니다. {x}구문을 사용하여 jsx 구성 요소 내부의 변수 값을 인쇄 하고 나중에 jsx 구성 요소를 렌더링 한 console.log (이전이 아님)을 사용하여 동일한 변수를 인쇄 할 수 있으며 console.log값이 부실 console.log하다는 것을 알 수 있습니다. 렌더링 후 발생 하는 값은 어떻게 든 이전 값을 가질 수 있습니다. 렌더링보다.

따라서 상태 변수의 실제 값은 일반 코드에서 항상 올바르게 작동하지 않을 수 있습니다. 렌더링에서 최신 값을 반환하도록 설계되었습니다. 이러한 이유로 상태 설정 기의 콜백 메커니즘은 렌더링 외부의 일반 코드에서 상태 변수의 최신 값을 가져올 수 있도록 구현되었습니다.