본문 바로가기
프로그래밍/웹 개발

[React] 함수 내 setState 사용 시, state 변경 순서와 타이밍 (에러핸들링)

by 제이콥J 2021. 11. 1.

프로젝트를 진행 중 요일(day)을 체크박스로 선택하여 state에 담는 기능을 구현했다.

 

이벤트함수 내에서 setState를 사용했다.

그러나 여기서 state가 변경되는 시점을 이해하지 못하여 에러가 발생했다.

 

문제 상황

1. 이벤트 함수 내에서 setState를 사용했으나, 다음 줄에서 여전히 state가 변경되지 않음

2. 이벤트 함수 내에서 또 다른 이벤트 함수를 사용했으나, 마찬가지로 변경전인 state를 사용하여 연산함

3. 코드

  - return 문은 생략

  - 수요일~일요일 정보를 담는 state와 함수는 생략

  - 클릭이벤트를 통해 monHandler와 tueHandler가 먼저 실행됨

 

export default function CompanyMyPage () {

  // 체크박스에서 선택된 요일을 배열로 담기 위한 state
  const [day, setDay] = useState([])

  // 선택된 각 요일을 나타내는 state
  const [mon, setMon] = useState([])
  const [tue, setTue] = useState([])

  // 각 요일의 체크 여부
  const [monChecked, setMonChecked] = useState(false)
  const [tueChecked, setTueChecked] = useState(false)

  // 체크된 요일을 day state에 모아주는 핸들러
  const dayHandler = () => {
    setDay([...mon, ...tue, ...wed, ...thu, ...fri, ...sat, ...sun])
  }

  // 클릭을 통해 월요일 정보를 mon state 에 추가하거나 빼는 핸들러 
  const monHandler = () => {
    setMonChecked(!monChecked) 
    if(monChecked) {  // 위 setMonChecked가 있지만 monChecked는 아직 변경되지 않음
      setMon(["월"])
    } else {
      setMon([])
    }
    dayHandler()  // 위에 setMon이 있지만 아직 mon state가 변경되지 않음
  }

  // 클릭을 통해 화요일 정보를 tue state 에 추가하거나 빼는 핸들러 
  const tueHandler = () => {
    setTueChecked(!tueChecked)
    if(tueChecked) {  // 위 settueChecked가 있지만 tueChecked는 아직 변경되지 않음
      setTue(["화"])
    } else {
      setTue([])
    }
    dayHandler()  // 위에 setTue이 있지만 아직 tue state가 변경되지 않음
  }

  return (

  )
}

 

원인

1. 실행 순서를 확인하니, monHandler 함수 내의 연산이 다 끝난 이후에 setMon을 통해 mon state가 변경됨

2. monHandler 내의 이벤트 함수인 dayHandler 또한 mon state가 변경되기 전에 실행됨

3. 이벤트함수 내의 setState는 해당 함수가 실행된 이후에 적용되어, 함수 내부의 연산은 setState의 영향을 받지 않음

 

해결방안

1. state 변경 전이므로, if 조건문 내부의 state에 '!'를 붙여 의도된 조건문이 발동되게 하기

2. 첫번째 이벤트 함수가 끝난 후에 두번째 이벤트 함수가 실행되도록, useEffect로 두번째 이벤트 함수 실행하기

3. 이 useEffect의 발동 조건은 첫번째 이벤트 함수를 통해 변경되는 state가 되어야 함

 

export default function CompanyMyPage () {

  // 체크박스에서 선택된 요일을 배열로 담기 위한 state
  const [day, setDay] = useState([])

  // 선택된 요일을 나타내는 state
  const [mon, setMon] = useState([])
  const [tue, setTue] = useState([])

  // 각 요일의 체크 여부
  const [monChecked, setMonChecked] = useState(false)
  const [tueChecked, setTueChecked] = useState(false)

  // 체크된 요일을 day state에 모아주는 핸들러
  const dayHandler = () => {
    setDay([...mon, ...tue, ...wed, ...thu, ...fri, ...sat, ...sun])
  }

  // 클릭을 통해 월요일 정보를 mon state 에 추가하거나 빼는 핸들러 
  const monHandler = () => {
    if(!monChecked) {  // setMonChecked를 통해 변경되기 전인 초기 state를 조건으로 사용
      setMon(["월"])
    } else {
      setMon([])
    }
    setMonChecked(!monChecked) 
  }

  // 클릭을 통해 화요일 정보를 tue state 에 추가하거나 빼는 핸들러 
  const tueHandler = () => {
    if(!tueChecked) {  // setTueChecked를 통해 변경되기 전인 초기 state를 조건으로 사용
      setTue(["화"])
    } else {
      setTue([])
    }
    setTueChecked(!tueChecked)
  }
  
  // 요일 state가 변경 이후에 dayHandler를 실행
  useEffect(() => {
    dayHandler()
  }, [mon, tue, wed, thu, fri, sat, sun])  // 변경된 요일 state를 실행 조건으로 설정

  return (
    
  )
}
반응형

댓글