강디너의 개발 일지

React setState를 동기적으로 사용해야할 때 본문

Javascript/React.js

React setState를 동기적으로 사용해야할 때

강디너 2023. 4. 30. 18:42
728x90

React에서 useState는 state값이 변경 될 때마다 해당 컴포넌트가 다시 렌더링을 하는 특성이 있습니다.

그래서 동기적으로 실행되는 자바스크립트 코드에서 setState를 실행하고 해당 state를 가지고 무슨짓을 하려고 할 때 이슈가 되는 경우가 있습니다.

 

예를 들어보겠습니다.

const [fruit, setFruit] = useState({
    banana: 0,
    apple: 0,
});

const [errors, setErrors] = useState({
    banana: false,
    apple: false,
})

 

여러가지 과일들이 있고, 과일이 있는지 여부를 체크할 것입니다.

가볍게 보면 banana와 apple이 0이라서 해당 조건문에 걸리고 setErrors를 하게됩니다.

그리고 checkError에 { banana: true, apple: true } 값이 나오는 것으로 예상되죠.

const validate = () => {
	console.log('검증시작');
    const { apple, banana } = fruit;

    if (banana === 0) {
        setErrors(prev => ({ ...prev, banana: true }));
    }
    if (apple === 0) {
        setErrors(prev => ({ ...prev, apple: true }));
    }
    // errors에 아직 반영이 되어있지 않다.
    const checkError = Object.values(errors).filter(i => i).length;
    console.log('checkError : ', errors, checkError);
    if (checkError > 0) {
      console.log('에러 확인');
      return;
    }
    
    // 검증을 통과하면 그대로 API 통신
    console.log('검증 통과');
}

하지만 콘솔은 아래와 같이 false false가 나옵니다. (리렌더링 전이고)

 

그리고 한번 더 클릭해야지 true값이 나오는 것을 볼 수 있습니다. (리렌더링 후라서)

 

이렇게 오류인 경우에도 검증이 통과되었다고 이후의 로직을 타게되면 예상하지 못한 문제가 발생 할 수 있습니다.

 

이런 경우 플래그 값을 하나 두고 검증 성공 여부를 알 수 있도록 하는 방법이 있습니다.

const validate = () => {
    console.log('검증시작');
    const { apple, banana } = fruit;

    const data = {
      apple: apple === 0,
      banana: banana === 0,
    };
    console.log(data);
    
    // 사용자에게 디테일한 오류를 보여주기 위해서
    // setErrors를 통해 apple, banana가 오류라는 것을 알려줘야한다.
    setErrors(prev => ({ ...prev, data}));
    
    const checkError = Object.values(data).filter(i => i).length;
    console.log('checkError : ', errors, checkError);
    if (checkError > 0) {
      console.log('에러 확인');
      setFinishValidate(false);
      return;
    }

    console.log('검증 통과');
    setFinishValidate(true);
  };

  useEffect(() => {
    if (finishValidate) {
      console.log('오류 검증 통과');
      // 검증을 통과했으니그대로 API 통신
    }
  }, [finishValidate]);

finishValidate라는 플래그를 주고, 성공할 경우에 값을 true로 변경합니다.

그 후 useEffect를 통해서 finishValidate가 true가 되었을 때 오류 검증 통과 후 로직을 적어줍니다.

 

 

 

apple과 banana의 값을 변경 후 테스트하면

 

주석에도 적었지만,

사용자에게 디테일한 오류를 보여주기 위해서는 setErrors를 통해서 apple, banana 값을 같이 변경해줘야합니다.

그 후 apple 오류에 대한 메시지를, banana 오류에 대한 메시지를 사용자에게 노출시킬 수 있습니다.

커피한잔...
Comments