Develop/React.js

[React] Redux

dawonny 2022. 8. 24. 04:16
728x90
반응형

장바구니 페이지를 만들려고 하는데 

장바구니에 들어갈 데이터들을 먼저 만들어보려고 한다.

근데 이 데이터들은 Cart.js에서만 쓰이는 것이 아니라 그 상위페이지에서도 쓰일 가능성이 있는데

 

이번에는 props 말고 redux를 이용해서 state 관리를 해보려고 한다.


Redux란?

Redux는 props없이 state를 공유할 수 있게 도와주는 라이브러리이다.

이걸 설치하면 js 파일 하나에 state 를 보관할 수 있는데

모든 컴포넌트에서 그 state 를 꺼내쓸 수 있다.

 

큰 사이트 일 수록 이 redux를 쓸 수 밖에 없어서 구인하는 거 보면 redux 숙련도를 요구한다.


Redux 쓰기

 

일단 설치부터 한다.

npm install @reduxjs/toolkit react-redux

터미널에 이걸 입력하고 

 

state 를 관리할 store.js 라는 파일을 하나 만들어주고

그 파일에 다음과 같이 작성을 해준다.

import { configureStore } from '@reduxjs/toolkit'

export default configureStore({
  reducer: { }
})

 

그리고 index.js 에 가서 Provider를 import 해오고

전체를 감싼다.

이렇게 하면 <App> 과 그 하위에 있는 모든 자식 컴포넌트들은 store.js에 있던 state 를 쓸 수 있게 되는 거다.

 

 

state 보관하기

 

store.js 파일에 다음과 같이 state 를 만들어서 등록한다.

createSlice 를 이용한다.

import { configureStore, createSlice } from "@reduxjs/toolkit";

let user = createSlice({
  name: "user",
  initialState: "kim",
});

let stock = createSlice({
  name: "stock",
  initialState: [10, 11, 12],
});

export default configureStore({
  reducer: {
    user: user.reducer,
    stock: stock.reducer,
  },
});

그리고 이 state 들을 가져다 쓰려면 다음과 같이 usesSelector 를 이용한다.

...

import { useSelector } from "react-redux";
function Cart() {
  let a = useSelector((state) => {
    return state;
  });

  return (
    <div>
    
 ...

a라는 변수에 저장했으니 이제

a

a.user

a.stock

이런식으로 데이터 바인딩이 가능하다.

 

let cartdata = createSlice({
  name: "cartdata",
  initialState: [
    { id: 0, name: "White and Black", count: 2 },
    { id: 2, name: "Grey Yordan", count: 1 },
  ],
});

cartdata 라는 state 를 만들어서

데이터 바인딩을 해본 모습이다.

import { useSelector } from "react-redux";
function Cart() {
  let a = useSelector((state) => {
    return state;
  });

  return (
    <div>
      <Table striped>
        <thead>
          <tr>
            <th>id</th>
            <th>Name</th>
            <th>Count</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>{a.cartdata[0].id}</td>
            <td>{a.cartdata[0].name}</td>
            <td>{a.cartdata[0].count}</td>
          </tr>
          <tr>
            <td>{a.cartdata[1].id}</td>
            <td>{a.cartdata[1].name}</td>
            <td>{a.cartdata[1].count}</td>
          </tr>
        </tbody>
      </Table>
    </div>
  );
}

 

map 을 이용해서 코드를 개선시켜봤다.

import { useSelector } from "react-redux";
function Cart() {
  let state = useSelector((state) => {
    return state;
  });

  return (
    <div>
      <Table striped>
        <thead>
          <tr>
            <th>id</th>
            <th>Name</th>
            <th>Count</th>
          </tr>
        </thead>
        <tbody>
          {state.cartdata.map((c, i) => (
            <tr>
              <td>{state.cartdata[i].id}</td>
              <td>{state.cartdata[i].name}</td>
              <td>{state.cartdata[i].count}</td>
            </tr>
          ))}
        </tbody>
      </Table>
    </div>
  );
}

state 변경 함수 만들기

 

일단 store.js에 state 를 수정하는 함수를 만든다.

slice 안에 reducers 라고 새로 만들어서 여기에 함수를 작성해주면 된다.

let user = createSlice({
  name : 'user',
  initialState : 'kim',
  reducers : {
    changeName(state){
      return 'john ' + state
    }
  }
})

그다음에 export 해준다.

export let { changeName } = user.actions

이걸 Cart.js 라는 파일에서 쓰고 싶을때에는 일단 저 changeName 함수를 import 해와주고

useDispatch 라는 걸 라이브러리에서 가져와준 후 

함수를 쓸때마다 dispatch로 감싸주면 된다.

import { useSelector, useDispatch } from "react-redux";
import { changeName } from "../store";

function Cart() {
  let state = useSelector((state) => {
    return state;
  });
  let dispatch = useDispatch();

  return (
    <div>
      {state.user}의 Cart
      <Table striped>
        <thead>
          <tr>
            <th>id</th>
            <th>Name</th>
            <th>Count</th>
          </tr>
        </thead>
        <tbody>
          {state.cartdata.map((a, i) => (
            <tr>
              <td>{state.cartdata[i].id}</td>
              <td>{state.cartdata[i].name}</td>
              <td>{state.cartdata[i].count}</td>
              <td>
                <button
                  onClick={() => {
                    dispatch(changeName());
                  }}
                >
                
                
                ...

 

이런 방식의 장점?

 

프로젝트가 커진다면 여러 컴포넌트에서 state 를 변경하다가 

state 값 버그가 나면

그 문제인 함수를 찾으려고 많은 컴포넌트를 찾아볼 필요가 없다.

 

지금 이 방식은 미리 state 변경함수는 store.js에다가 만들어놓고

컴포넌트는 그 함수를 실행해달라고 부탁만 하는 식이기 때문에 디버깅에 용이하다.


state 가 object나 array 일 경우

 

let user = createSlice({
  name : 'user',
  initialState : {name : 'kim', age : 20},
  reducers : {
    changeName(state){
      state.name = 'park'
    }
  }
})

이런식으로 직접 state 를 수정할 수 있다.

 

만약에 파라미터를 받는 함수를 만들고 싶다면( 5라는 파라미터라면 5만큼 증가..)

다음과 같이 payload를 써준다.

let user = createSlice({
  name : 'user',
  initialState : {name : 'kim', age : 20},
  reducers : {
    increase(state, a){
      state.age += a.payload
    }
  }
})

 

728x90
반응형