[javascript] useState 후크 세터가 상태를 잘못 겹쳐 씁니다.

문제가 있습니다 : 버튼 클릭으로 2 개의 함수를 호출하려고합니다. 두 함수 모두 상태를 업데이트합니다 (useState 후크를 사용하고 있습니다). 첫 번째 함수는 value1을 ‘new 1’로 올바르게 업데이트하지만 1s (setTimeout) 후에 두 번째 함수가 실행되고 값 2가 ‘new 2’로 변경되지만 BUT! value1을 다시 ‘1’로 설정했습니다. 왜 이런 일이 발생합니까? 미리 감사드립니다!

import React, { useState } from "react";

const Test = () => {
  const [state, setState] = useState({
    value1: "1",
    value2: "2"
  });

  const changeValue1 = () => {
    setState({ ...state, value1: "new 1" });
  };
  const changeValue2 = () => {
    setState({ ...state, value2: "new 2" });
  };

  return (
    <>
      <button
        onClick={() => {
          changeValue1();
          setTimeout(changeValue2, 1000);
        }}
      >
        CHANGE BOTH
      </button>
      <h1>{state.value1}</h1>
      <h1>{state.value2}</h1>
    </>
  );
};

export default Test;



답변

폐쇄 지옥에 오신 것을 환영합니다 . 때마다 때문에이 문제가 발생 setState라고하며, state새로운 메모리 참조를 가져옵니다 만, 기능 changeValue1changeValue2때문에 폐쇄는 이전 초기 유지 state참조.

용액 보장 setState발을 changeValue1하고 changeValue2최신의 상태가 사용하는 것이다 얻는다 콜백 (파라미터로서 이전 상태를 갖는)

import React, { useState } from "react";

const Test = () => {
  const [state, setState] = useState({
    value1: "1",
    value2: "2"
  });

  const changeValue1 = () => {
    setState((prevState) => ({ ...prevState, value1: "new 1" }));
  };
  const changeValue2 = () => {
    setState((prevState) => ({ ...prevState, value2: "new 2" }));
  };

  // ...
};

이 폐쇄 문제에 대한 자세한 내용은 여기여기를 참조하십시오 .


답변

당신의 기능은 다음과 같아야합니다 :

const changeValue1 = () => {
    setState((prevState) => ({ ...prevState, value1: "new 1" }));
};
const changeValue2 = () => {
    setState((prevState) => ({ ...prevState, value2: "new 2" }));
};

따라서 조치가 실행될 때 이전 상태를 사용하여 현재 상태의 기존 특성이 누락되지 않았는지 확인하십시오. 또한 클로저를 관리하지 않아도됩니다.


답변

changeValue2호출, 상태의 회전이 inital 상태로 있도록 초기 상태는 유지되고 다음 value2속성이 기록됩니다.

changeValue2후 다음 에 호출되면 state가 유지 {value1: "1", value2: "new 2"}되므로 value1속성을 덮어 씁니다.

setState매개 변수에 화살표 기능이 필요합니다 .

const Test = () => {
  const [state, setState] = React.useState({
    value1: "1",
    value2: "2"
  });

  const changeValue1 = () => {
    setState(prev => ({ ...prev, value1: "new 1" }));
  };
  const changeValue2 = () => {
    setState(prev => ({ ...prev, value2: "new 2" }));
  };

  return (
    <React.Fragment>
      <button
        onClick={() => {
          changeValue1();
          setTimeout(changeValue2, 1000);
        }}
      >
        CHANGE BOTH
      </button>
      <h1>{state.value1}</h1>
      <h1>{state.value2}</h1>
    </React.Fragment>
  );
};

ReactDOM.render(<Test />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>


답변

무슨 일이 일어나고 있는지 changeValue1와 둘 다 생성 된 렌더changeValue2 에서 상태 볼 수 있으므로 구성 요소를 처음 렌더링 할 때이 두 함수는 다음을 참조하십시오.

state= {
  value1: "1",
  value2: "2"
}

버튼을 클릭 changeValue1하면가 먼저 호출되고 상태가 {value1: "new1", value2: "2"}예상대로 변경 됩니다.

이제 1 초 후에이 changeValue2함수가 호출되지만이 함수는 여전히 초기 상태 ( {value1; "1", value2: "2"})를 확인하므로이 함수는 다음과 같이 상태를 업데이트합니다.

setState({ ...state, value2: "new 2" });

당신은보고 : 결국 {value1; "1", value2: "new2"}.

출처


답변