[React] Redux, Toolkit

JiHyun·2023년 3월 4일
0
post-thumbnail

redux란?
useState를 통해 상태를 관리했을 때 발생하는 불편함을 일부 덜어주는 전역 상태(Global State)관리 라이브러리이다. 여러 컴포넌트가 동일한 상태를 공유할 수 있으며, 액션 및 리듀서의 사용으로 상태 변경의 추적 및 디버깅이 쉬워진다.

전역 상태관리에서 state를 생성하고, 만약 어떤 컴포넌트에서 state가 필요하다면 컴포넌트가 어디에 위치하고 있든 상관없이 state를 불러와서 사용할 수 있다.

1. redux 설치

yarn add react-redux redux
redux 폴더 정리
redux : 리덕스 관련 코드 모두
config : 중앙 state 관리소 -> 설정 코드(.js)
modules : state의 그룹. 

2. 폴더구조잡기

[public] 
  - index.html
    
[src] 
  - App.js
  - index.js
  > [component]
		- Counter.js(예시)
  > [redux] 
     > [config]
        - configStore.js
            
     > [modules]  // reducer 폴더
        - counterContainer.js(예시)
        - userContainer.js(예시)

3-1. 중앙 state 관리소(store) 만들기

configStore.js

과정
1. 사용할 reducer import하기
2. reducer를 합칠 rootReducer 만들기
3. reducer 합치기
4. rootReducer 를 기반으로 중앙 state관리소인 store생성
import { createStore, combineReducers } from "redux"
// reducer import
import counter from '../modules/counterContainer'; // 사용할 reducer
import user from '../modules/userContainer';       // 사용할 reducer(현재 포스팅에서는 사용안함 예시일뿐임)

// rootReducer 생성
const rootReducer = combineReducers({
  // reducer들 합치기
  counter,
  user,
});

// store 생성
const store = createStore(rootReducer);

export default store;

createStore - store를 만드는 API
combineReducers - redux를 하나로 묶어주는 API

3-2. 최상위 컴포넌트 import하기

index.js

// Provider을 사용하기위한 import
import { Provider } from 'react-redux';
import store from './redux/config/configStore';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  // 사용할 전역상태관리만큼 Provider로 감싸기
  // 전역 데이터인 store을 props로 넘겨줌
  <Provider store={store}>
    <App />
  </Provider>
);
reportWebVitals();

3-3. 컴포넌트 만들기

Counter.js

과정
1. useSelector를 사용해서 store접근 -> reducer 조회
2. CRUD를 위한 useDispatch사용
3. dispatch를 사용해서 함수 만들기(인자로 액션함수 사용해 reducer 적용하기)
import { plusN, minusN } from '../modules/counterContainer';
import { useState } from 'react';
// 값을 수정하기 위한 import
import { useSelector } from 'react-redux';
import { useDispatch } from 'react-redux';

function Counter() {
  // useSelector를 사용해 store(configStore)에 접근해서 reducer 읽어오는 과정
  const counter = useSelector((state) => {
    return state.counter;
  });
  
  // state를 변경(CRUD)하기 위해선 useDispatch를 사용해야함
  const dispatch = useDispatch()
  
  const [number, setNumber] = useState(0);

  return (
    <>
      <p>현재 카운트 : {counter.number}</p>
	  <div>
        <input
          type="number"
          value={number}
          onChange={(event) => {
            // 비구조분해 할당
            const { value } = event.target;
            // +를 넣어주면 문자열->숫자열로 형변환됨
            setNumber(+value);
          }}
        />
      </div>
      <button
		// action 객체를 리턴해주는 함수(액션 함수)를 넣어서 하드코딩 막기
		// 액션함수 인자로 payload 넣어주기
        onClick={() => dispatch(plusN(number)) }>
        +
      </button>

      <button 
		onClick={() => dispatch(minusN(number)) }>
        -
      </button>
  	</>;
}

export default Counter;

3-3. reducer

counterContainer.js

과정
1. action value만들기
2. action creater(액션 함수)만들기
3. state의 초기값 지정
4. 리듀서 선언
// (1) 사람의 실수를 방지하기위해 action의 type을 변하지않는 상수로 만들기
const PLUS_N = 'counter/PLUS_N';
const MINUS_N = 'counter/MINUS_N';


// (2) action value를 return 하는 action creater 함수
export const plusN = (payload) => {
  return {
    type: PLUS_N,
    payload,
  };
};
export const minusN = (payload) => {
  return {
    type: MINUS_N,
    payload,
  };
};

// (3) 초기 상태값(state) 지정
const initialState = {
  number: 0,
};


// (4) 리듀서 선언
              // 매개변수 - state, action
			  // state의 초기값을 할당해줌
const counter = (state = initialState, action) => {
  // state를 action의 type에 따라 함수가 적용되게 switch case문 사용
  switch (action.type) {
    case PLUS_N: 
      return {
        number: state.number + action.payload,
      };
    case MINUS_N:
      return {
        number: state.number - action.payload,
      };
    default:  // 어디에도 해당되지않은 값
      return state;
  }
};

export default counter;

4. App.js에 컴포넌트 import

import React from 'react';
import Counter from './redux/component/Counter';

function App() {
  return (
    <div>
      <Counter />
    </div>
  );
}
export default App;

+) Redux Toolkit

Redux Toolkit?
Redux를 사용하여 상태 관리를 좀 더 쉽고 간단하게 만들어주는 도구 모음이다. Redux-Toolkit을 사용하면 Redux를 사용하여 상태를 관리하는 데 필요한 여러 가지 요소를 쉽게 생성할 수 있다. 이를 통해 Redux를 더 쉽고 간단하게 사용할 수 있으며, 코드의 가독성과 유지 보수성이 향상된다.

Redux-Toolkit의 기능

  • configureStore: Redux 스토어를 구성하는 데 사용되며 상태를 관리하는 데 필요한 초기 설정을 단순화시켜준다.
  • createSlice: Action Creator와 Reducer를 한번에 생성할 수 있게끔 만들어준 API.
  • createAsyncThunk: 비동기 작업을 수행할 때 사용된다. 이를 통해 비동기 작업의 시작, 진행 및 완료에 대한 액션을 생성할 수 있으며, Redux-Thunk보다 간단하게 사용할 수 있습니다.

configStore.js

// 일반 리듀서
const rootReducer = combineReducers({
  counter,
  user,
});

const store = createStore(rootReducer);

// Redux-Toolkit
const store = configureStore({
  reducer: {
    counter,
    user,
  },
});

기존에는 reducer들을 합치기위해 rootReducer를 만들고 이를 기반으로 중앙 state관리소인 store를 생성해야 했다면 Toolkit에서는 combineReducers와 createStore를 합친 configureStore를 활용하여 바로 store로 만들고 store객체안에 reducer를 넣어주면 된다.

reducer
일반 redux

const PLUS_N = 'counter/PLUS_N';
const MINUS_N = 'counter/MINUS_N';


// action creater
export const plusN = (payload) => {
  return {
    type: PLUS_N,
    payload,
  };
};
export const minusN = (payload) => {
  return {
    type: MINUS_N,
    payload,
  };
};

// 초기 상태값
const initialState = {
  number: 0,
};


// reducer
const counter = (state = initialState, action) => {
  switch (action.type) {
    case PLUS_N:   
      return {
        number: state.number + action.payload,
      };
    case MINUS_N:
      return {
        number: state.number - action.payload,
      };
    default:
      return state;
  }
};

export default counter;

Redux-Toolkit

// 초기 상태값
const initialState = {
  number: 0,
};

//createSlice
const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
  	plusN: (state, action) => {
      state.number = state.number + action.payload;
    },
    minusN: (state, action) => {
      state.number = state.number - action.payload;
    },
  }
})
export default counterSlice.reducer;
export const { plusN, minusN } = counterSlice.actions;

createSlice는 Action creater와 reducer를 한번에 생성할 수 있게 만들어주는 API이다. reducers내의 프로퍼티에는 action creater 이름을 넣고 값에는 콜백함수를 넣어준다.

profile
비전공자의 개발일기📝

0개의 댓글