ABOUT ME

Today
Yesterday
Total
  • [React] Redux
    codeStates front-end/React 2023. 2. 24. 18:20
    반응형

     

     

    📌  Redux

     

     

     

    📍Redux 개요

     

    보통 리액트에서 최상위 컴포넌트 -> 부모 컴포넌트 -> 자식 컴포넌트가 일반적이지만,

    다소 비효율적이라고 느낄 수 있다.

     

    1. 해당 상태를 직접 사용하지 않는 최상위 컴포넌트, 컴포넌트1, 컴포넌트2도 상태 데이터를 가짐

    2. 상태 끌어올리기, Props 내려주기를 여러 번 거쳐야 함

    3. 애플리케이션이 복잡해질수록 데이터 흐름도 복잡해짐

    4. 컴포넌트 구조가 바뀐다면, 지금의 데이터 흐름을 완전히 바꿔야 할 수도 있음

     

    허나 Redux는 전역 상태를 관리할 수 있는 저장소인 Store를 제공함으로써 이 문제들을 해결

     

     

     

     

     

     

    📍Redux 구조

     

     

    🔗 Redux 상태 관리

     

    Action → Dispatch → Reducer → Store 순서

     

    1. 상태가 변경되어야 하는 이벤트가 발생하면, 변경될 상태에 대한 정보가 담긴 Action 객체가 생성
    2. 이 Action 객체는 Dispatch 함수의 인자로 전달
    3. Dispatch 함수는 Action 객체를 Reducer 함수로 전달
    4. Reducer 함수는 Action 객체의 값을 확인하고, 그 값에 따라 전역 상태 저장소 Store의 상태를 변경
    5. 상태가 변경되면, React는 화면을 다시 렌더링 

     

    🔗 Redux  설치

     

    npm install redux react-redux

     

    🔗 Store

     

    상태 관리되는 오직 하나뿐인 저장소의 역할

     

    // createStore 메서드를 활용해 Reducer를 연결 -> Store 생성
    import { createStore } from 'redux';
    
    const store = createStore(rootReducer);

     

    Store 실습

     

    // App.js
    
    import React from 'react';
    import './style.css';
    
    export default function App() {
      return (
        <div>
          <h1>{`Count: ${1}`}</h1>
        </div>
      );
    }
    
    // index.js
    import React from 'react';
    import { createRoot } from 'react-dom/client';
    import App from './App';
    import { Provider } from 'react-redux';
    import { legacy_createStore as createStore } from 'redux';
    
    const rootElement = document.getElementById('root');
    const root = createRoot(rootElement);
    
    const reducer = () => {};
    
    const store = createStore(reducer);
    
    root.render(
     <Provider store={store}>
      <App />
     </Provider>
    );

     

    🔗 Reducer

    Reducer는 Dispatch에게서 전달받은 Action 객체의 type 값에 따라서 상태를 변경시키는 함수

    Reducer는 순수함수여야 한다

     

     

     

    Reducer 실습

     

    import React from 'react';
    import { createRoot } from 'react-dom/client';
    import App from './App';
    import { Provider } from 'react-redux';
    import { legacy_createStore as createStore } from 'redux';
    
    const rootElement = document.getElementById('root');
    const root = createRoot(rootElement);
    
    const count = 1;
    
    // Reducer를 생성할 때에는 초기 상태를 인자로 요구합니다.
    const counterReducer = (state = count, action) => {
      // Action 객체의 type 값에 따라 분기하는 switch 조건문입니다.
      switch (action.type) {
        //action === 'INCREASE'일 경우
        case 'INCREASE':
          return state + 1;
    
        // action === 'DECREASE'일 경우
        case 'DECREASE':
          return state - 1;
    
        // action === 'SET_NUMBER'일 경우
        case 'SET_NUMBER':
          return action.payload;
    
        // 해당 되는 경우가 없을 땐 기존 상태를 그대로 리턴
        default:
          return state;
      }
    };
    
    const store = createStore(counterReducer);
    
    root.render(
      <Provider store={store}>
        <App />
      </Provider>
    );

     

    💡여러 개의 Reducer를 사용하는 경우

     

    // combineReducers 메서드를 사용해서 하나의 Reducer로 합쳐준다
    import { combineReducers } from 'redux';
    
    const rootReducer = combineReducers({
      counterReducer,
      anyReducer,
      ...
    });

     

    🔗 Action

     

    Action은 말 그대로 어떤 액션을 취할 것인지를 정의해놓은 객체

    Action객체를 생성하는 함수를 만들어 사용하는 경우가 많다

     

    type -> 필수로 지정(대문자와 Snake Case), 필요에 따라 payload를 작성해 구체적인 값을 전달

     

    // Action객체 직접 작성
    
    // payload가 필요 없는 경우
    { type: 'INCREASE' }
    
    // payload가 필요한 경우
    { type: 'SET_NUMBER', payload: 5 }
    
    // Action 생성자
    
    // payload가 필요 없는 경우
    const increase = () => {
      return {
        type: 'INCREASE'
      }
    }
    
    // payload가 필요한 경우
    const setNumber = (num) => {
      return {
        type: 'SET_NUMBER',
        payload: num
      }
    }

     

    Action  실습

     

    import React from 'react';
    import { createRoot } from 'react-dom/client';
    import App from './App';
    import { Provider } from 'react-redux';
    import { legacy_createStore as createStore } from 'redux';
    
    const rootElement = document.getElementById('root');
    const root = createRoot(rootElement);
    
    export const increase = () => {
      return {
        type: 'INCREASE'
      }
    }
    
    export const decrease = () => {
      return {
        type: 'DECREASE'
      }
    }
    
    
    
    const count = 1;
    
    // Reducer를 생성할 때에는 초기 상태를 인자로 요구합니다.
    const counterReducer = (state = count, action) => {
      // Action 객체의 type 값에 따라 분기하는 switch 조건문입니다.
      switch (action.type) {
        //action === 'INCREASE'일 경우
        case 'INCREASE':
          return state + 1;
    
        // action === 'DECREASE'일 경우
        case 'DECREASE':
          return state - 1;
    
        // action === 'SET_NUMBER'일 경우
        case 'SET_NUMBER':
          return action.payload;
    
        // 해당 되는 경우가 없을 땐 기존 상태를 그대로 리턴
        default:
          return state;
      }
      // Reducer가 리턴하는 값이 새로운 상태가 됩니다.
    };
    
    const store = createStore(counterReducer);
    
    root.render(
      <Provider store={store}>
        <App />
      </Provider>
    );

     

    🔗 Dispatch

     

    Dispatch는 Reducer로 Action을 전달해주는 함수

    Dispatch의 전달인자로 Action 객체가 전달

     

    // Action 객체를 직접 작성하는 경우
    dispatch( { type: 'INCREASE' } );
    dispatch( { type: 'SET_NUMBER', payload: 5 } );
    
    // 액션 생성자(Action Creator)를 사용하는 경우
    dispatch( increase() );
    dispatch( setNumber(5) );

     

    🔗 Redux Hooks

     

    Redux Hooks는 React-Redux에서 Redux를 사용할 때 활용할 수 있는 Hooks 메서드를 제공

    useSelector(), useDispatch()

     

    useDispatch()

     

    Action 객체를 Reducer로 전달해 주는 Dispatch 함수를 반환하는 메서드

     

    import { useDispatch } from 'react-redux'
    
    const dispatch = useDispatch()
    dispatch( increase() )
    console.log(counter) // 2
    
    dispatch( setNumber(5) )
    console.log(counter) // 5

     

    useSelector()

     

    컴포넌트와 state를 연결하여 Redux의 state에 접근할 수 있게 해주는 메서드

     

    // Redux Hooks 메서드는 'redux'가 아니라 'react-redux'에서 불러옵니다.
    import { useSelector } from 'react-redux'
    const counter = useSelector(state => state)
    console.log(counter) // 1

     

     

    useDispatch(), useSelector() 실습 - Redux 예제

     

    import React from 'react';
    import './style.css';
    // react-redux에서 useDispatch, useSelector 사용
    import { useDispatch, useSelector } from 'react-redux';
    // index.js에서 action객체 함수 사용
    import { increase, decrease } from './index.js';
    
    export default function App() {
      // Reducer로 전달해 주는 Dispatch 함수를 반환하는 메소드
      const dispatch = useDispatch();
      // useSelector() 사용하여 redux가 state에 접근할수 있게 한다
      const state = useSelector((state) => state);
      console.log(state);
    
      const plusNum = () => {
      // 이벤트 함수에 dispatch 함수를 사용하여 값을 저장
        dispatch(increase());
      };
    
      const minusNum = () => {
      // 이벤트 함수에 dispatch 함수를 사용하여 값을 저장
        dispatch(decrease());
      };
    
      return (
        <div className="container">
          {/* 화면에 렌더링 하기 위해 state값을 템플릿리터럴에 넣어준다 */}
          <h1>{`Count: ${state}`}</h1>
          <div>
            <button className="plusBtn" onClick={plusNum}>
              +
            </button>
            <button className="minusBtn" onClick={minusNum}>
              -
            </button>
          </div>
        </div>
      );
    }

     

     

     

    Redux의 세 가지 원칙

    Redux에는 세 가지 원칙이 있습니다. 각각의 원칙이 Redux의 어떤 구성 요소와 연결이 되는지 확인하세요.

    1. Single source of truth

    동일한 데이터는 항상 같은 곳에서 가지고 와야 한다는 의미입니다. 즉, Redux에는 데이터를 저장하는 Store라는 단 하나뿐인 공간이 있음과 연결이 되는 원칙입니다.

    2. State is read-only

    상태는 읽기 전용이라는 뜻으로, React에서 상태갱신함수로만 상태를 변경할 수 있었던 것처럼, Redux의 상태도 직접 변경할 수 없음을 의미합니다. 즉, Action 객체가 있어야만 상태를 변경할 수 있음과 연결되는 원칙입니다.

    3. Changes are made with pure functions

    변경은 순수함수로만 가능하다는 뜻으로, 상태가 엉뚱한 값으로 변경되는 일이 없도록 순수함수로 작성되어야하는 Reducer와 연결되는 원칙입니다.

    반응형

    'codeStates front-end > React' 카테고리의 다른 글

    [React] 번들링과 웹팩  (0) 2023.03.20
    [React]Cmarket Redux  (0) 2023.02.27
    [React] Storybook, useRef  (0) 2023.02.20
    [React] custom component/ Styled-Component  (0) 2023.02.20
    [React] UX 디자인  (0) 2023.02.15

    댓글

Designed by Tistory.