꾸준히 성장하는 개발자

[React 라이브러리] 상태 관리 라이브러리 Redux 본문

React

[React 라이브러리] 상태 관리 라이브러리 Redux

ahleum 2022. 5. 20. 10:20

 

Redux 란?

 

Redux = Reducer + Flux

flux 아키텍쳐에 reducer라는 개념을 도입

 

  Javascript app을 위한 예측 가능한(predictable) state container이다 

  리액트 뿐만 아니라 Augular, jQuery, vanilla JavaScript 등 다양한 framework와 작동되게 설계되어 있다.

모든 전역 state를 하나의 거대한 object에 모두 담아서 관리한다. 

 

Redux 쓰는 이유

1. props 문법 귀찮을 때 사용

    - 모든 component가 props 없이 state 직접 꺼낼 수 있음

 

2. state 변경 관리할때 사용

  - state가 버그가 생겨도 추적이 쉬워 찾기 쉽다

 

 

하지만 난 지금 React랑 같이 쓸 거니까 설치는 React-redux도 같이 진행하겠다.

 

설치방법

npm i redux react-redux

 

여기에서 우리의 목표는 Left3에서 나오는 숫자를 Right3에서 누르는 버튼으로 숫자 증가를 시켜볼 것이다. 

만약 Redux가 없다면 number값을 props를 통해서 전달이 되는데

Right3 → Right2→ Right1→ Roof→ Left1 →Left2→ Left3

const [number, setNumber]= useState(1);


function Left1(props) {
  return (
    <div>
      <h1>Left1 : {props.number}</h1>
      <Left2 number={props.number}></Left2>
    </div>
  );
}
function Left2(props) {
  return (
    <div>
      <h1>Left2 :{props.number} </h1>
      <Left3 number={props.number}></Left3>
    </div>
  );
}

이렇게 넘겨줘야 할것이다. 

그런데 Redux의 state를 사용한다면 좀 더 편하게 전달이 가능하다

 

이제 Redux를 사용해보자

 

import { createStore } from 'redux';
import { Provider, useSelector, useDispatch, connect } from 'react-redux';

redux를 사용하기 위해 createStore을 불러온다.

 

Provider: component, 

             state를 어떤 component에 제공할 것인가 에 대한 가장 바깥쪽의 울타리를 정하는 것

useSelector: 어떤 state값을 쓰고 싶은지 선택할 때 사용

useDispatch: state값을 변경시킬 때 사용

connect: 재사용을 할 때 사용 / 지금은 사용하지 않는다

 

 

 

state 수정하는 방법   /  reducer

reducer 

- flux 아키텍쳐 중 dispatcher를 대체

 - 현재 state와 들어온 action을 이용하여 다음 state를 결정하는 순수함수

           (순수함수란? 동일한 인자가 들어갈 경우 항상 같은 값이 나오는것 

              function add(a,b){a+b} => add(1,2) => 3 반환 

            )

 - state의 자료형은 자유 (primitive, 배열, 객체 등)

 - 상태를 update한다면 대입 연산이 아닌 다음 state를 반환. (immutable)

 

store 

- 하나의 거대한 object

- store에 reducer를 등록

- dispatch된 action을 모든 reducer에게 전달

- store가 처음 생성될 때 INIT action을 reducer에게 전달하여 초기 state를 저장

// state의 관리를 하는 전용 장소 or 앱의 상태를 보관하는 Redux 저장소
const store=createStore(reducer);

// state를 어떻게 바꿀것인가
function reducer(현재state값, 어떻게 바꿀것인지 요청을 받는 액션){
  // 만약 state가 정의되지 않았다면?
  if(현재state값 === undefined){
  	return{
    	number : 기존값,
    }
  }
  // redux는 각각의 state의 변화를 불변하게 유지해야 하는데 어떻게 유지하느냐
  // 새로운 state를 만드는데 과거의 state를 복제한다.
  const 새로운state = { ... 현재state}  
  return 새로운 state 값
}

redux는 각각의 state의 변화를 불변하게 유지해야 하는데 어떻게 유지하느냐

 -> 새로운 state를 만드는데 과거의 state를 복제한다.

 

 

const [number, setNumber]= useState(1);

그리고 우린 이 값은 필요가 없어졌으니 지우도록 한다. 

function reducer(currentState, action) {
  if (currentState === undefined) {
    return {
      number: 1,
    };
  }
  const newState = { ...currentState };
  if (action.type === 'PLUS') {
    newState.number++;
  }
  return newState;
}
const store = createStore(reducer);

 

 

Provider

react-redux 라이브러리에 내장되어있는, 리액트 앱에 store를 손쉽게 연동할 수 있도록 도와주는 컴포넌트

이 컴포넌트를 불러온 다음에, 연동할 컴포넌트를 감 싸준 다음에Provider 컴포넌트의 props로 store 값을 설정해준다.

Provider를 사용하면서 prop 중에 store라는 것을 반드시 정의해줘야 한다.

store는 위에 useStore( )를 정의해놓은 것을 가져오면 된다.

const store = createStore(reducer);
export default function App() {
  return (
    <div id="container">
      <h1>Root</h1>
      <div id="grid">
        <Provider store={store}>
          <Left1></Left1>
          <Right1></Right1>
        </Provider>
      </div>
    </div>
  );
}

 

 

 

 useSelector 

현재 우리는 위의 number값을 무선으로 연결하고 싶은 것인데

그래서 사용하는 것은 useSelector이다. 

function Left3(props) {
  console.log('3');
  const number = useSelector((state) => state.number);
  return (
    <div>
      <h1>Left3 : {number}</h1>
    </div>
  );
}

useSelector는 함수를 인자로 받는다.

function f(state){ 
    return state.number
}
const number=useSelector(f);

이렇게 작성되는 것을 위처럼 좀 더 간단하게 작성할 수 있는 것이다. 

 

 

dispatch

우리는 저기에 있는 number값을 Right3에서 바꿔줄 수 있는 button을 설정해보자

function Right3(props) {
  const dispatch = useDispatch();
  return (
    <div>
      <h1>Right3</h1>
      <input
        type="button"
        value="+"
        onClick={() => {
          dispatch({ type: 'PLUS' });
        }}
      ></input>
    </div>
  );
}

dispatch를 가져와서 

onClick에 'PLUS'라는 action을 전달한다. 그렇게 되면 reducer가 호출된다. 

액션을 선언할때에는 위와 같이 대문자로 선언한다.

 

 

 

 

import React, { useState } from 'react';
import './style.css';
import { createStore } from 'redux';
import { Provider, useSelector, useDispatch, connect } from 'react-redux';
function reducer(currentState, action) {
  if (currentState === undefined) {
    return {
      number: 1,
    };
  }
  const newState = { ...currentState };
  if (action.type === 'PLUS') {
    newState.number++;
  }
  return newState;
}
const store = createStore(reducer);
export default function App() {
  return (
    <div id="container">
      <h1>Root</h1>
      <div id="grid">
        <Provider store={store}>
          <Left1></Left1>
          <Right1></Right1>
        </Provider>
      </div>
    </div>
  );
}
function Left1(props) {
  return (
    <div>
      <h1>Left1 </h1>
      <Left2></Left2>
    </div>
  );
}
function Left2(props) {
  console.log('2');
  return (
    <div>
      <h1>Left2 : </h1>
      <Left3></Left3>
    </div>
  );
}
function Left3(props) {
  console.log('3');
  const number = useSelector((state) => state.number);
  return (
    <div>
      <h1>Left3 : {number}</h1>
    </div>
  );
}
function Right1(props) {
  return (
    <div>
      <h1>Right1</h1>
      <Right2></Right2>
    </div>
  );
}
function Right2(props) {
  return (
    <div>
      <h1>Right2</h1>
      <Right3></Right3>
    </div>
  );
}
function Right3(props) {
  const dispatch = useDispatch();
  return (
    <div>
      <h1>Right3</h1>
      <input
        type="button"
        value="+"
        onClick={() => {
          dispatch({ type: 'PLUS' });
        }}
      ></input>
    </div>
  );
}

 


https://www.youtube.com/watch?v=yjuwpf7VH74&t=53s 

진상현강사님 강의 + 생활코딩 유투브에서 배운 내용 정리 완료

 

https://stackblitz.com/edit/react-pf1cxs?file=src%2FApp.js 

 

React-Redux : with redux final - StackBlitz

 

stackblitz.com

 

 

'React' 카테고리의 다른 글

[React Hooks] useRef  (0) 2022.05.23
[React] React state 비동기성  (0) 2022.05.20
React with Typescript 설치  (0) 2022.05.19
[React] API를 이용한 data 가져오기  (0) 2022.05.12
React - jsx , state, props  (0) 2022.05.06