클래스안에서는 this.setState에 두번째 인자가 들어가면 이미 첫번째인자에서 업데이트한 state를 두번째 인자에서 받아서 사용가능하다.
그러나 useState에서 setState는 그 기능이 제공되지 않고 있다. 애초에 첫번째 인자만 받아들 일 수 있다.
그러나 여러가지 방법으로 가능하다. useEffect, useRef를 조합해서 customHook을 만들 수 있고, use-state-with-callback
라는 라이브러리를 사용해도 된다.
그럼 알아보자
// npm install use-state-with-callback
import useStateWithCallback from 'use-state-with-callback';
const SomeOtherComponent = () => {
const [count, setCount] = useStateWithCallback(0, count => {
if (count > 1) {
document.title = 'Threshold of over 1 reached.';
} else {
document.title = 'No threshold reached.';
}
});
return (
<div>
<p>{count}</p>
<button type="button" onClick={() => setCount(count + 1)}>
Increase
</button>
</div>
);
};
function useStateCallback(initialState) {
const [state, setState] = useState(initialState);
const cbRef = useRef(null);
const setStateCallback = useCallback((state, cb) => {
cbRef.current = cb;
setState(state);
}, [])
// useCallback을 이용해서 cb의 reference를 유지해준다
// 그리고 Ref에 저장한다
// 그리고 state를 업데이트 한다.
useEffect(() => {
if (cbRef.current) {
cbRef.current(state);
cbRef.current = null;
}
}, [state]);
// useEffect를 이용해서 setStateCallback을 통해 state가 업데이트 되면 useEffect안에 있는 함수가 실행된다.
// Ref안에 저장해두었던 두번째 인자 ,callback 함수에 업데이트 된 state를 넣고 실행한다.
// 그다음 ReF를 초기화 시켜 다음 들어올 callback을 받을 준비를 한다.
return [state, setStateCallback];
}
const App = () => {
const [state, setState] = useStateCallback(0);
const handleClick = () =>
setState(
prev => prev + 1,
// important: use `s`, not the stale/old closure value `state`
s => console.log("I am called after setState, state:", s)
);
return (
<div>
<p>Hello Comp. State: {state} </p>
<button onClick={handleClick}>Click me</button>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
짠! 자세한 설명은 주석을 참고!
적극적으로 customHook을 만들어볼 생각을 하자.
독립적으로 state를 관리해보자!