Redux
상태 관리를 위한 라이브러리.
useState와 같은 기능을 제공하나, 해당 컴포넌트에서만 사용되는 useState와 달리 전역적으로 사용이 가능하다.
- 설치
npm i redux react-redux
사용하기 위해서 먼저 전체적인 redux의 구조를 이해할 필요가 있다.
redux는 action, dispatch, reducer, store로 구성되어 있다.
action : 상태를 변경시킬 action 정의.
dispatch : 상태를 업데이트 하기 위한 메서드, action을 전달해줌.
reducer : 현재 state와 전달받은 action을 토대로 새로운 상태를 반환해줌.
store : reducer로부터 전달받아 상태를 생성.
동작 과정을 살펴보면,
- 컴포넌트에서 특정 이벤트가 발생하면, action을 dispatch함수를 이용해 store에 전달한다.
- 전달받은 action은 스토어에 직접적으로 저장되지 않고 reducer로 보내지게 되며, reducer에서는 기존의 state값을 store에서 불러오고, 이와 action을 추가해 새로운 state값을 반환한다.
- store는 새로운 state값을 저장하며 이에 상태의 변화가 발생한다.
- 컴포넌트와 store는 subscribe(구독)되어 있기 때문에, 상태에 변화가 발생할시 리렌더링하게 된다.
조금 더 간편한 이해를 위해 아래 코드를 통해 useState에 비유해보겠다.
const [plist, setPlist] = useState([]);
...
//dispatch합수를 통해 action을 보내는 과정
const list = { title: title, body: body, writer: member};
//reducer에서 기존의 state값을 불러옴
const newplist = [...plist];
//reducer에서 기존의 state값에 action을 더함
newplist.push(list);
//store에서 reducer에서 전달받은 상태를 업데이트함
setPlist(newplist);
//구독에 의해 상태 변화를 인지하고 리렌더링함
setMode('POST');
- 사용법
이제 사용방법에 대해서 알아보자.
살펴보니 사람마다 조금씩 다르게 사용하는 듯하다.
일단 여기서는 총 5개의 파일로 redux를 구성할 것이다.
파일구조는
redux
ㄴstore.js
ㄴactions
ㄴitemActions.js
ㄴtype.js
ㄴreducers
ㄴindex.js
ㄴitemReducer.js
이렇게 되어 있다.
먼저 스토어부터 구성하겠다.
<store.js>
import { createStore, applyMiddleware, compose } from 'redux';
import {thunk} from 'redux-thunk';
import rootReducer from './reducers';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
rootReducer,
composeEnhancers(
applyMiddleware(thunk)
)
);
export default store;
여기서 applyMiddleware는 axios등의 미들웨어를 사용하게 된다면 필요한 것이다.
react앱을 생성하면 만들어지는 기존의 index.js 파일을 다음과 같이 수정하여야 자식 파일에서 store를 사용할 수 있다.
<index.js>
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import store from './redux/store';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App />
</Provider>
);
<itemActions.js>
import axios from 'axios';
import { FETCH_ITEMS } from './type';
export const fetchItems = () => {
return dispatch => {
axios.get('http://localhost:8000/api/item')
.then(response => {
const items = response.data;
dispatch({
type: FETCH_ITEMS,
payload: items
});
})
};
};
위 코드는 DB를 사용하려다 보니 axios함수를 사용하게 되어서 저런 형태이지만, 중요한 것은 type과 payload(데이터 값)이다.
<type.js>
export const FETCH_ITEMS = 'FETCH_ITEMS';
관리의 편의를 위해 따로 분리하였다.
이제 액션을 받아줄 reducer가 필요하다.
<itemReducer.js>
import { FETCH_ITEMS } from '../actions/type';
const initialState = {
items: []
};
const itemReducer = (state = initialState, action) => {
switch (action.type) {
case FETCH_ITEMS:
return {
...state,
items: action.payload
};
default:
return state;
}
};
export default itemReducer;
초기 상태를 위한 initialState를 생성하여주고(useState의 초기화에 해당), itemReducer를 통해 새로운 상태를 만든다(setState).
여기서 저 return안에서 ...state는 기존의 상태를 복사함을 의미하며, 뒤에 오는 item객체를 추가하며 반환한다.
<index.js>
import { combineReducers } from 'redux';
import itemReducer from './itemReducer';
const rootReducer = combineReducers({
items: itemReducer
});
export default rootReducer;
구조에 맞춰서 정리하여준다.
이렇게 하면 스토어의 내부 구성은 완료되며, 이제 이 상태값을 이용하기만 하면 된다.
import { useDispatch, useSelector } from 'react-redux';
import { fetchItems } from '../redux/actions/itemActions';
const dispatch = useDispatch();
const item = useSelector(state => state.items.items);
useDispatch함수를 통해 컴포넌트에서도 action이 가능하며, useSelector함수를 통해 구독의 역할을 할 수 있다.
'React' 카테고리의 다른 글
[React] useEffect의 무한루프 에러 (1) | 2024.07.24 |
---|---|
[React] useMemo (0) | 2024.07.24 |
[React] Swiper (0) | 2024.03.13 |
[React] react에서 이미지 엑박이 뜰 때 (0) | 2024.03.07 |
[React] useEffect (0) | 2024.02.28 |