- useReducer
- useReducer는 컴포넌트에서 상태변화 로직을 분리하기 위해 사용한다.
const [state, dispatch] = useReducer(reducer, initialState);
-----------------------------------
function reducer(state, action) {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
default:
return state;
}
}
-------------------------------------
dispatch({ type: 'INCREMENT' }); // 상태를 증가시키는 액션 디스패치
dispatch({ type: 'DECREMENT' }); // 상태를 감소시키는 액션 디스패치
- 기본적으로 useReducer는 위와 같이 사용된다.
1. reducer : 상태를 어떻게 업데이트할지를 결정하는 함수이다. 이 함수는 현재 상태('state')와 액션('action')을 받아서 새로운 상태를 반환한다.
2. initialState : 상태의 초기값을 나타낸다. useReducer를 호출 할 때 이 값을 제공한다.
3. useReducer : 이 두 가지 인자를 받아 현재 상태('state')와 액션을 디스패치하는 함수 ('dispatch')를 반환한다.
4. 상태를 업데이트하기 위해 'dispatch' 함수를 사용한다. 'dispatch' 함수는 액션을 인자로 받고, 이 액션은 'reducer' 함수에 전달되어 상태를 업데이트하게 된다.
// const [data, setData] = useState([]);
const [data, dispatch] = useReducer(reducer, []);
- 기존의 useState 함수를 아래와 같이 useReducer 함수로 변경 할 수 있다.
- data의 초기화 값은 빈 배열로 초기화 된다.
const onCreate = useCallback((author, content, emotion) => {
const created_date = new Date().getTime();
const newItem = {
author,
content,
emotion,
created_date,
id: dataId.current,
};
dataId.current += 1;
setData((data) => [newItem, ...data]);
함수형 업데이트
}, []);
- 기존의 useState를 사용할 때 data 변수도 외부에 종속적으로 동작하였다.
const onCreate = useCallback((author, content, emotion) => {
dispatch({
type: "CREATE",
data: { author, content, emotion, id: dataId.current },
});
dataId.current += 1;
}, []);
- useReducer를 사용하게 되면, 위와 같이 외부에 종속적인 데이터 없이, 필요한 값을 외부에 전달하여 원하는 상태를 반환 받을 수 있게 된다.
- dispatch 안의 작성된 type에 의해 reducer 함수에서 switch에서 해당 type과 동일한 ("CREATE")를 찾아 상태 변화를 시킨다.
- 위와 같이 상태 변화를 위해 추가적으로 필요한 데이터를 전달 할 수 있다. dispatch에 의해 전달된 값들은 action 객체에 속하게 되고, action.type, action.data와 같이 호출하여 사용할 수 있다.
const reducer = (state, action) => {
switch (action.type) {
case `INIT`: {
return action.data;
}
case `CREATE`: {
const created_date = new Date().getTime();
const newItem = {
...action.data,
created_date,
};
return [newItem, ...state];
}
- 위의 onCreate에서 전달된 dispatch에 의해 type이 CREATE인 case를 찾아 실행하게 된다.
- onCreate에서 전달된 dispatch의 data 값이 action.data를 통해 호출된 것을 확인 할 수 있다.
- 결과적으로 return으로 반환된 값이 state의 값을 변화시키고 최종적으로 useReducer의 data의 값을 변화시키게 된다.
- Context
- Context란 React 애플리케이션에서 전역 상태를 관리하고 데이터를 컴포넌트 트리 내에서 공유하는 방법을 제공하는 기능이다. Context를 사용하면 상위 컴포넌트에서 하위 컴포넌트로 데이터를 명시적으로 전달하지 않고도 데이터를 공유할 수 있으며, 컴포넌트 간의 상태 및 설정을 전역으로 관리할 수 있다.
- 사용 방법
1. React.createContext()를 통해 Context 객체를 생성한다. (export로 생성해야 한다. 외부에 전달하는 것이기 때문이다.)
2. 부모 컴포넌트에서 "객체명".Provider value={전달할 prop} 를 통해 하위 컴포넌트로 전파시킨다.
3. 상위 컴포넌트로부터 전달 받기위해선 const {전달받은 prop 중 사용할 prop} = useContext("Context 객체명"); 을 통해 상위 컴포넌트로부터 prop을 전달 받아 사용할 수 있다.
- 아래 코드들을 통해 사용 방법에 대해 알아보겠다.
- App.js
const [data, dispatch] = useReducer(reducer, []);
const onCreate = useCallback((author, content, emotion) => {
dispatch({
type: "CREATE",
data: { author, content, emotion, id: dataId.current },
});
//onCreate처럼 컴포넌트가 onEdit, onRemove가 있다고 가정한다.
................
export const DiaryStateContext = React.createContext();
export const DiaryDispatchContext = React.createContext();
// Context 객체를 생성해준다.
// 두개를 나눠서 사용하는 이유는 아래 Provider로 전달할 때 결국 Context도 prop이기 때문에
// 상태가 변경되면 계속해서 리렌더링 되기 떄문이다.
.................
const memoizedDispatches = useMemo(() => {
return { onCreate, onRemove, onEdit };
}, []);
.............
return (
<DiaryStateContext.Provider value={data}>
<DiaryDispatchContext.Provider value={memoizedDispatches}>
..............
- Context 객체를 2개로 나눈 이유는 state 상태를 나타내는 data와, 상태 변화 함수를 나누기 위해서이다.
- memoizedDispatches는 useMemo를 통해 onCreate, onRemove, onEdit 함수가 리렌더링 될 때 마다 재 생성되는 것을 방지한다.
return (
<DiaryStateContext.Provider value={data}>
<DiaryDispatchContext.Provider value={memoizedDispatches}>
- 위 코드를 통해 하위 컴포넌트 어디든 value={data}, valu={memoizedDispatches}를 호출하여 사용할 수 있게 된다.
- DiaryEditor.js
...........
const DiaryEditor = () => {
const { onCreate } = useContext(DiaryDispatchContext);
............
onCreate(state.author, state.content, state.emotion);
alert("저장 성공");
setState({
author: "",
content: "",
emotion: "",
});
};
- useContext{}를 이용하여 부모 컴포넌트의 Provider 중 원하는 컴포넌트를 받아서 사용할 수 있다.
'Portfolio, Project > Project(Programming)' 카테고리의 다른 글
React - 페이지 구현(1) (최상위 컴포넌트 (App.js), Home 페이지 작성) (0) | 2023.09.25 |
---|---|
React - React Router 기본, 응용 / useParams / useSearchParams / useNavigate (0) | 2023.09.24 |
React - useMemo / React.memo / useCallback (0) | 2023.09.20 |
React - 리스트 렌더링 / 데이터 추가, 삭제, 수정 / useEffect (useEffect... 내용 저장 안함... ) (0) | 2023.09.19 |
React - 사용자 입력 처리 / DOM 조작(useRef) / API 호출 (0) | 2023.09.18 |