본문 바로가기

React

[React] Redux

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