콜백함수 형태로 state 업데이트
버튼을 한번 클릭했을때 state의 count가 5씩 증가하는 콜백함수를 만들어보자.
const [count, setCount] = useState(0); const onIncrease = () => { setCount(count + 1); //1 setCount(count + 1); //1 setCount(count + 1); //1 setCount(count + 1); //1 setCount(count + 1); //1 };
위와 같이 처리하면 콜백함수 실행시 5씩 증가할까 ? 아니다.
자바스크립트 클로저와 관련이 있는데, 콜백함수가 전달될때 현재상태를 스냅샷을 한다. 스냅샷이 될때 외부변수 count 값이 0으로 저장된다.
그래서 아무리 많이 setCount를 호출해도 count가 0으로 고정되어있으므로 1이다.
setState 를 정의하는 방법에는 한번에 값을 정의하는 방법과 이전 상태값을 인자로 전달하는 콜백함수 형태로 전달하는 방법이 있다.
const [count, setCount] = useState(0); const onIncrease = () => { setCount((prev) => prev + 1); setCount((prev) => prev + 1); setCount((prev) => prev + 1); setCount((prev) => prev + 1); setCount((prev) => prev + 1); };
이렇게 이전 상태값을 인자로 받아서 업데이트를 하면 된다.
여러 상태값 합치기
여러 컴포넌트들의 상태값을 합쳐서 표현해주려면 어떻게 해야할까?
부모컴포넌트에 setState 함수를 정의한 후 그걸 props로 자식 컴포넌트들에 전달한다.
export default function AppCounter() { const [count, setCount] = useState(0); const handleClick = () => setCount((prev) => prev + 1); return ( <div className="container"> <div className="banner"> Total Count : {count} {count > 10 ? "😍" : "🥰"} </div> <div className="counters"> <Counter total={count} onClick={handleClick} /> <Counter total={count} onClick={handleClick} /> </div> </div> ); }
export default function Counter({ total, onClick }) { const [count, setCount] = useState(0); const onIncrease = () => { setCount((prev) => prev + 1); }; return ( <div className="counter"> <span className="number">{count}</span>{" "} <span className="total">/{total}</span> <button className="button" onClick={() => { onIncrease(); onClick(); }} > Add + </button> </div> ); }
그래서 위와 같이 하위 컴포넌트들의 state도 변경하면서 전체 count 역시 증가시킬 수 있다.
정리
state를 업데이트하는 함수는 기존에 스냅샷된 외부값에 의존하기 보다는, callback 함수 형태로 set 하는것이 안전하다.
여러 state를 종합할 필요가 있을때는 부모 컴포넌트에 setState를 선언 후 자식 컴포넌트에 props로 전달한다.