React

 

 

 리덕스 설정

 

1. 리덕스 설치:

먼저 리덕스를 설치해야 합니다. 아래의 명령어를 사용하여 설치할 수 있습니다.

 

npm install redux react-redux

 

 

 

2. 리듀서 정의:

리듀서는 액션에 따라 상태를 어떻게 변경할지를 정의하는 함수입니다.

여러 개의 리듀서를 사용하는 경우, combineReducers 메소드를 사용하여 하나로 묶어줍니다.

 

rootReducer

import  { combineReducers }  from "redux";
import  counter  from "./counter";

const  rootReducer =  combineReducers({
  counter
});

export default  rootReducer;

 

 

 

3.스토어 생성:

 createStore 함수를 사용하여 스토어를 생성합니다. 이때 리듀서를 인자로 전달합니다.

 

import  { createStore }  from "redux";
import  rootReducer  from './reducers';

const  store =  createStore(rootReducer);

 

 

 

4.리액트 앱에 리덕스 적용

Provider 컴포넌트를 사용하여 리액트 앱에 스토어를 제공합니다

 Provider 컴포넌트는 리액트 컴포넌트를 감싸며, store prop에 스토어를 전달합니다.

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import App from './App';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

 

이렇게 설정하면 리액트 앱에서 리덕스를 사용할 수 있게 됩니다.

이 외에도 리덕스 미들웨어를 사용하거나, 리덕스 개발 도구를 설정하는 등의 추가적인 설정을 할 수 있습니다. 

 

 

 

예)

스토어

store/index.js

import { createStore } from "redux";
import { createSlice } from "@reduxjs/toolkit";


const initialState = { counter: 0, showCounter: true };
createSlice({
  name:'counter',
  initialState:initialState,
  
})

const counterReducer = (state = initialState , action) => {
  switch (action.type) {
    case "increment":
      return {
        counter: state.counter + 1,
        showCounter: state.showCounter,
      };
    case "increase":
      return {
        counter: state.counter + action.amount,
        showCounter: state.showCounter,
      };

    case "decrement":
      return {
        counter: state.counter - 1,
        showCounter: state.showCounter,
      };

    case "toggle":
      return {
        counter: state.counter ,
        showCounter: !state.showCounter,
      };


    default:
      return state;
  }
};

const store = createStore(counterReducer);

export default store;

 

 

Counter.jsx

useDispatch,   useSelector

import { useSelector, useDispatch } from "react-redux";
import classes from "./Counter.module.css";

const Counter = () => {
  const dispatch = useDispatch();
  const counter = useSelector((state) => state.counter);
  const show=useSelector(state=>state.showCounter);

  const incrementHandler = () => {
    dispatch({
      type: "increment",
    });
  };
  const increaseHandler = () => {
    dispatch({
      type: "increase",
      amount: 5,
    });
  };

  const decrementHandler = () => {
    dispatch({
      type: "decrement",
    });
  };

  const toggleCounterHandler = () => {
    dispatch({
      type: "toggle",
    });
  };

  return (
    <main className={classes.counter}>
      <h1>Redux Counter</h1>
      {show && <div className={classes.value}>{counter} </div> }
      <div>
        <button onClick={incrementHandler}>Increment</button>
        <button onClick={increaseHandler}>Increment by 5</button>
        <button onClick={decrementHandler}>Decrement</button>
      </div>
      <button onClick={toggleCounterHandler}>Toggle Counter</button>
    </main>
  );
};

export default Counter;

 

 

1. useDispatch 임포트: 먼저 react-redux에서 useDispatch를 임포트합니다.

 

import { useDispatch } from 'react-redux';

 

2. useDispatch 사용: useDispatch를 호출하여 dispatch 함수를 가져옵니다.

const dispatch = useDispatch();

 

3.액션 디스패치: dispatch 함수를 사용하여 액션을 디스패치합니다. 이때 액션은 액션 생성 함수를 통해 생성할 수 있습니다.

dispatch(myAction());

 

위의 코드에서 myAction는 액션 생성 함수입니다.

이렇게 useDispatch를 사용하면 리덕스 스토어의 액션을 실행시킬 수 있습니다.

이 외에도 useSelector와 같은 훅을 사용하여 리덕스 스토어의 상태에 접근할 수 있습니다.

 

 

 

 

 

 

※리덕스 툴킷을 설정하는 방법

 

1.리덕스 툴킷 설치: 리덕스 툴킷을 설치하려면 다음 명령어를 사용합니다.

# NPM을 사용하는 경우
npm install @reduxjs/toolkit react-redux

# Yarn을 사용하는 경우
yarn add @reduxjs/toolkit react-redux

 

 

2.리덕스 툴킷 적용: 리덕스 툴킷을 설치하려면 다음 명령어를 사용합니다.

리덕스 툴킷을 적용하려면 configureStore를 사용하여 스토어를 생성합니다. 이때, configureStore의 인자로 리듀서를 포함하는 객체를 전달합니다.

import { configureStore } from "@reduxjs/toolkit";
import counter from "../modules/counterSlice";

const store = configureStore({
  reducer: {
    counter: counter.reducer,
  },
});

export default store;

 

 

 

3. Slice 생성: 
createSlice를 사용하여 Slice를 생성합니다. 
createSlice는 객체를 인자로 받으며, 이 객체에는 name, initialState, reducers가 필요합니다.

 

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

const initialState = {
  number: 0,
};

const counterSlice = createSlice({
  name: "counter",
  initialState,
  reducers: {
    addNumber: (state, action) => {
      state.number = state.number + action.payload;
    },
    minusNumber: (state, action) => {
      state.number = state.number - action.payload;
    },
  },
});

export default counterSlice;
export const { addNumber, minusNumber } = counterSlice.actions;

 

 

4.컴포넌트에서 사용:

컴포넌트에서는 useSelector와 useDispatch를 사용하여 리덕스 스토어의 상태를 조회하거나 액션을 디스패치할 수 있습니다

import { useSelector, useDispatch } from "react-redux";
import { RootState } from "../store";
import { down, init, up } from "../store/counterSlice";

function Counter() {
  const dispatch = useDispatch();
  const count = useSelector((state: RootState) => {
    return state.counter.value;
  });

  const addNumber = () => {
    dispatch(up(2));
  };

  const minusNumber = () => {
    dispatch(down(2));
  };

  const initNumber = () => {
    dispatch(init(""));
  };

  return (
    <div>
      <div>{count}</div>
      <button onClick={addNumber}>+</button>
      <button onClick={minusNumber}>-</button>
      <button onClick={initNumber}>초기화</button>
    </div>
  );
}

export default Counter;

 

 

5.index.js 설정

import ReactDOM from 'react-dom/client';
import {Provider} from 'react-redux';
import './index.css';
import App from './App';
import store from './store';


const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Provider  store={store} ><App /></Provider>);

 

 

 

 

이렇게 설정하면 리덕스 툴킷을 사용하여 상태 관리를 할 수 있습니다.

리덕스 툴킷은 기존의 리덕스보다 설정이 간편하고, 코드량도 줄일 수 있어 많이 사용되고 있습니다.

 

 

 

 

 

 

 

 

 

※리덕스를 리덕스 툴킷으로 변경하는 방법

 

리덕스 툴킷은 리덕스의 기능을 간소화하고 향상시키는 라이브러리로, 리덕스, 리덕스 개발자 도구 확장, 리덕스 thunk 등을 내장하고 있습니다.

따라서 이러한 패키지들을 따로 설치할 필요가 없습니다.

리덕스 툴킷을 사용하면 액션 생성자와 리듀서를 더 쉽게 작성할 수 있으며, 미들웨어 설정, 상태 정규화, 비동기 로직 처리 등의 복잡한 작업을 단순화할 수 있습니다.

따라서 리덕스 툴킷을 사용하면 리덕스를 더 효과적으로 사용할 수 있습니다.

 

 

 

1. 리덕스 툴킷 설치: 먼저, 리덕스 툴킷을 설치하고, 기본적으로 포함되어 있는 패키지를 제거합니다.

npm i @reduxjs/toolkit  react-redux
npm uninstall redux redux-devtools-extension redux-thunk

 

2.configureStore 사용: createStore를 리덕스 툴킷의 configureStore로 대체하고, 리듀서를 configureStore에 전달합니다. 
이 함수는 스토어 객체를 반환합니다.


3.createSlice 사용: 기존의 액션 생성자와 리듀서를 createSlice로 대체합니다. 
이 함수는 액션 생성자와 리듀서를 자동으로 생성합니다.

 


위의 코드를 리덕스 툴킷으로 변경하면 다음과 같습니다:

 

 

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

const initialState = { counter: 0, showCounter: true };

const counterSlice =createSlice({
  name:'counter',
  initialState:initialState,
  reducers:{
    increment(state){
      state.counter++;
    },
    decrement(state){
      state.counter--;
    },
    increase(state, action){
      state.counter +=action.payload;
    },
    toggleCounter(state){
      state.showCounter = !state.showCounter;
    }
  }
});



const store=configureStore({
  reducer: {counter:counterSlice.reducer, } 
});


//export const { increment, increase, decrement, toggle } = counterSlice.actions;
//or
export const counterActions =counterSlice.actions;

export default store;

 

 

이 코드는 기존의 리덕스 코드를 리덕스 툴킷으로 변경한 것입니다. 
 

좋은점:

1)이제 액션 타입을 수동으로 정의할 필요가 없으며, 액션 생성자와 리듀서는 createSlice에 의해 자동으로 생성됩니다
 

2) 알아서  불변성을 유지

기존의 리덕스에서는 상태를 변경할 때마다 새로운 상태 객체를 생성해야 했습니다. 
이는 상태가 직접 수정되지 않도록 하기 위한 것이었습니다. 그러나 이렇게 하면 코드가 복잡해지고 버그가 발생하기 쉬웠습니다.

반면에 리덕스 툴킷의 createSlice 함수는 Immer 라이브러리를 내장하고 있어, 상태를 직접 수정하는 것처럼 코드를 작성할 수 있습니다. 
그러나 실제로는 Immer가 상태의 불변성을 유지하면서 새로운 상태를 생성합니다. 
따라서 리덕스 툴킷을 사용하면 상태를 불변하게 유지하는 것이 더 쉽고, 코드도 더 간결해집니다.

 

 

위와 같이 리덕스 툴킷의 store 을 설정 했다면 다음과 같은 처리방식으로 데이터의 이용이 가능하다.

import { useSelector, useDispatch } from "react-redux";
import classes from "./Counter.module.css";

import { counterActions } from "../store";



const Counter = () => {
  const dispatch = useDispatch();
  const counter = useSelector((state) => state.counter);
  const show=useSelector(state=>state.counter.showCounter);

  const incrementHandler = () => {
    dispatch(counterActions.increment());
  };

  const increaseHandler = () => {
    //리덕스 툴킷은 자동으로 action 생성하고 리덕스 툴킷이 생성한 {type: SOME_UNIQUE_IDENTIFIER, payload:10}
    dispatch(counterActions.increase(10));
  };

  const decrementHandler = () => {
    dispatch(counterActions.decrement());
  };

  const toggleCounterHandler = () => {
    dispatch(counterActions.toggleCounter());
  };

  return (
    <main className={classes.counter}>
      <h1>Redux Counter</h1>
      {console.log("show :",show)}

      {show && <div className={classes.value}>{counter.counter} </div> }
      <div>
        <button onClick={incrementHandler}>Increment</button>
        <button onClick={increaseHandler}>Increment by 5</button>
        <button onClick={decrementHandler}>Decrement</button>
      </div>
      <button onClick={toggleCounterHandler}>Toggle Counter</button>
    </main>
  );
};

export default Counter;

 

 

 

 

 

※ 리덕스 툴킷 코드 분할하기

 

1.store/index.js

import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./counter";
import authReducer from "./auth";


const store=configureStore({
  reducer: {
    counter:counterReducer, 
    auth:authReducer
  } 
});



export default store;

 

 

 

 

2.store/auth.js

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


const initialAuthState={
  isAuthenticated:false,
  user:null
}

const authSlice=createSlice({
  name:'authentication',
  initialState:initialAuthState,
  reducers:{
    login(state){
      state.isAuthenticated=true;
    },
    logout(state){
      state.isAuthenticated=false;
    },    
  }
})


export const authActions =authSlice.actions;

export default authSlice.reducer;

 

 

 

 

3.store/counter.js

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

const initialState = { counter: 0, showCounter: true };

const counterSlice =createSlice({
  name:'counter',
  initialState:initialState,
  reducers:{
    increment(state){
      state.counter++;
    },
    decrement(state){
      state.counter--;
    },
    increase(state, action){
      state.counter +=action.payload;
    },
    toggleCounter(state){
      state.showCounter = !state.showCounter;
    }
  }
});


export const counterActions =counterSlice.actions;

export default counterSlice.reducer;

 

 

 

 

Header.js 에서 사용예

import classes from "./Header.module.css";
import { useSelector, useDispatch } from "react-redux";
import { authActions } from "../store/auth";


const Header = () => {
  const dispatch=useDispatch();
  const isAuth = useSelector((state) => state.auth.isAuthenticated);

  const logoutHandler =(e)=>{    
    e.preventDefault();
    dispatch(authActions.logout());
  }

  return (
    <header className={classes.header}>
      <h1>리덕스 인증</h1>
      {isAuth && (
        <nav>
          <ul>
            <li>
              <a href="/">내 제품</a>
            </li>
            <li>
              <a href="/">내 매출</a>
            </li>
            <li>
              <button onClick={logoutHandler}>로그아웃</button>
            </li>
          </ul>
        </nav>
      )}
    </header>
  );
};

export default Header;

 

 

 

 

Counter.js  예서 사용 예

import { useSelector, useDispatch } from "react-redux";
import classes from "./Counter.module.css";

import { counterActions } from "../store/counter";



const Counter = () => {
  const dispatch = useDispatch();
  const counter = useSelector((state) => state.counter);
  const show=useSelector(state=>state.counter.showCounter);

  const incrementHandler = () => {
    dispatch(counterActions.increment());
  };

  const increaseHandler = () => {
    //리덕스 툴킷은 자동으로 action 생성하고 리덕스 툴킷이 생성한 {type: SOME_UNIQUE_IDENTIFIER, payload:10}
    dispatch(counterActions.increase(10));
  };

  const decrementHandler = () => {
    dispatch(counterActions.decrement());
  };

  const toggleCounterHandler = () => {
    dispatch(counterActions.toggleCounter());
  };

  return (
    <main className={classes.counter}>
      <h1>리덕스 카운터</h1>
      {console.log("show :",show)}

      {show && <div className={classes.value}>{counter.counter} </div> }
      <div>
        <button onClick={incrementHandler}>증가</button>
        <button onClick={increaseHandler}>5씩 증가</button>
        <button onClick={decrementHandler}>감소</button>
      </div>
      <button onClick={toggleCounterHandler}>카운터 전환</button>
    </main>
  );
};

export default Counter;

 

 

 

 

소스 : https://github.com/braverokmc79/macaronics-react-calculatoror

dev: https://github.dev/braverokmc79/macaronics-react-calculatoror

사이트 :

https://macaronics-react-calculatoror.netlify.app/

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

about author

PHRASE

Level 60  라이트

웨이터의 매너가 좋으면, 어떤 술이라도 미주(美酒)가 된다. -탈무드

댓글 ( 0)

댓글 남기기

작성