useReducer를 이용해서 커스텀 state를 만들수 있다. todo이니깐 todo가 변할 때 마다, localStorage에 저장해보도록 하자. 그렇게 해서 reducer를 만들면 context에 저장해놓고 필요할 때 바로 꺼내 쓰는거다.
// useLocalStorageReducer.js
export default funtion useLocalStorageReducer(key,defaultVal,todoReducer) {
const [todos, dispatch] = useReducer(todoReducer,defaultVal,()=>{
let value;
try {
value = JSON.parse(localStorage.getItem(key)) || [];
} catch (error) {
value = defaultVal;
}
return value;
})
useEffect(() => {
localStorage.setItem(key, JSON.stringify(todos));
}, [todos, key]);
return [todos, dispatch];
}
useReducer의 3번째 인자에는 DefaultVal을 세팅하는 함수가 들어간다. 요렇게 해놓고 todoContext에서 사용하면 된다.
// todoContext.js
import { createContext } from 'react';
import todoReducer from '../todoReducer';
import useLocalStorageReducer from '../Hooks/useLocalStorageReducer';
export const dispatchContext = createContext('');
export const todoContext = createContext('');
const initTodos = [];
export default function TodoContextWrapper(props) {
const [todos, dispatch] = useLocalStorageReducer(
'todos',
initTodos,
todoReducer
);
return (
<todoContext.Provider value={todos}>
<dispatchContext.Provider value={dispatch}>
{props.children}
</dispatchContext.Provider>
</todoContext.Provider>
);
}
불필요한 랜더링을 막기위해서 context를 두가지로 쪼갰다. 그럼 dispatch만 사용되는 곳에서는 todos가 바뀌더라도 랜더링이 일어나지 않는다. 만약 context를 하나로 합치고 todos,dispatch 두개다 동시에 보내면 todos가 바뀔때 dispatch만 사용되는 곳도 같이 랜더링 된다.
그럼 끝!