처음하는 Redux

김범식·2023년 4월 19일
0
post-thumbnail

next.js를 배우려고 하니 전역 변수를 redux로 관리한다는 이야기를 들었다. react를할 때는 전역변수를 recoil로 관리했기 때문에 redux에 대해서는 전무했다. 이번기회에 redux의 기초를 정리하려 한다.





🎁 state는 세가지 경우가 았다.


  • local state : 하나의 컴포넌트에서 이루어지는 상태 값 (버튼 토글 등.. )
  • Cross-Component state : props로 내려주는 값 && props 드릴링
  • App-Wide State : 사용자인증, 로그인하면 탐색바를 변경해야함 , props드릴링이 깊거나 복잡해지면 app-wide State를 즉 전역변수를 사용한다.




🎁 리덕스를 사용해야 하는 이유!


리액트 컨텍스트가 있는데 왜 리덕스를 사용해야하는가?

리액트 컨텍스트의 단점

  • 설정이 복잡해진다.
  • 애플리케이션 종류에 따라 복잡성이 높아진다.

  • 중첩이 아주 심해진것을 볼 수 있다.
  • 데이터 변경이 많은 경우 별로 좋지 않다고 한다.




🎁 리덕스 동작 방식


하나의 중앙 데이터 저장소이다. 2개가 아닌 1개, 여기서 모든 데이터를 저장하게 된다.

사용 하는 경우

  • 인증 상태, 테마(다크모드), 등을 저장할 수 있다.
  • 우리는 이 상태를 구독하고 클라이언트사이드에서 ui를 그리게 된다.
    ex) 태마가 다크모드면 다크모드를 그림




컴포넌트는 데이터를 직접 조작하지 않는다.

그 대신 우리는 리듀서함수라는 것으로 조작하게 된다.

이 함수는 변형을 담당한다. useReducer와 다르다. , 입력을 변환해서 결과를 반환한다는 뜻의 리듀서 함수이다. 데이터 저장소의 업데이트를 담당한다.

이런 데이터를 트리거하는건 component이다. actiondispatch한다.
action은 뭐고 dispatch는 무엇인가??? 지금은 몰라도 된다. 밑에서 코드로 직접 확인해보자





실제 코드 내용


react 코드에서 사용하지 않더라도 redux를 따로 사용할 수 있다.

  1. redux-demo.js파일 작성
  2. npm init -y
  3. npm install redux





    react가 아닌 node에서 구현한 redux
const redux = require("redux"); //node.js에서 import 해 올때 이와같은 방법을 사용한다.

//두개의 파라미터와 한개의 새로운 값을 출력해야 한다.
//험수 안에는 부수적인 효과가 없어야한다. 전역 변수를 관리하는 코드만 들어가있어야한다.
const counterReducer = (state = {counter:0}, action) => {

    if(action.type === "increment"){
        return {
          counter: state.counter + 1, //state는 이전상태를 의미하기 때문에 거기에 1을 더한값이 출력되게 된다.
        };
    }
    if(action.type === "decrement"){
        return {
            counter : state.counter - 1,
        }
    }
};

//어떤 함수가 조작중인지 알아야하기 때문에 createStore의 인자로 counterReducer가 들어가게 된다.
const store = redux.createStore(counterReducer);

//구독하기
const counterSubscriber = () => {
  const latestState = store.getState();
  console.log(latestState);
};

store.subscribe(counterSubscriber);
store.dispatch({type:"increment"});
store.dispatch({type:"decrement"});
  1. reducer를 정의한다.
  2. redux에 넣어 store를 정의한다.
  3. counterSubscriver를 정의한다.
  4. store.subscribe를 정의한다. 이 함수는 store의 state가 변경될때마다. 실행되는 함수이다.
  5. dipatch로 action을 넘겨서 state를 조작한다.
  6. react에서 쓸거면 이건 몰라도 됨 ㅎ




React에서 redux 사용하기






설치

npm install redux react-redux






src/store/index.js

import { legacy_createStore as createStore } from "redux";

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

const counterReducer = (state = initialState, action) => {
  console.log(action.action);
  switch (action.type) {
    case "increment":
      return {
        ...state,
        counter: state.counter + 1,
      };
    case "increase":
      return {
        ...state,
        counter: state.counter + action.amount,
      };
    case "decrement":
      return {
        ...state,
        counter: state.counter - 1,
      };
    case "toggle":
      return {
        ...state,
        showCounter: !state.showCounter,
      };
    default:
      return state;
  }
};

const store = createStore(counterReducer);

export default store;

다음은 redux를 사용하는 기본적인 모습을 담고 있다 이제 코드를 하나하나 살펴보자

import { legacy_createStore as createStore } from "redux";
// import { createStore } from "redux";  이렇게 써도 상관없는데 취소선 생겨서 거슬림

store를 만들어 주는 createStore를 import 받는데 특이한 점은 legacy_createStore이라는 점이다. 현재 redux에는 createStore 대신에 configureStore이라는 함수를 권장하고 있는데, 그거때문에 그냥 createStore를 사용하면 createStore에 취소선이 생긴다. 여기서는 굳이 configureStore사용해 줄 필요가 없고, 취소선이 보기 불편하기 때문에 legacy_createStore를 사용했다.




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

전역으로 관리할 초기값을 세팅해준다. 숫자 증가를 보기 위한 counter와 토글버튼 활성화를 위한 showCounter가 있다.




const counterReducer = (state = initialState, action) => {
  console.log(action.action);
  switch (action.type) {
    case "increment":
      return {
        ...state,
        counter: state.counter + 1,
      };
    case "increase":
      return {
        ...state,
        counter: state.counter + action.amount,
      };
    case "decrement":
      return {
        ...state,
        counter: state.counter - 1,
      };
    case "toggle":
      return {
        ...state,
        showCounter: !state.showCounter,
      };
    default:
      return state;
  }
};
  • counterReducer : 하나의 리듀서를 만들어둔다. 이 리듀서를 통해 전역으로 변수를 관리한다.
  • state : 초기 값을 의미한다. , 초기값을 세팅해주었다.
  • action : 값을 어떻게 변경해 줄지 action으로 입력받은 값에 의해 결정된다.
  • …state : redux는 절대 기존값을 변경해서 return하지 않는다, 기존값을 복사해서 변형이 필요한 부분만 고처서 사용한다. 기존 객체를 변경하고 반환하면 참조값을 사용하는건데 그러면 에러가 발생할 확률이 높고 디버깅하기 힘들다고 한다.




const store = createStore(counterReducer);
export default store;

store로 하나의 store를 마들어준다. 이값을 이용해서 다른 컴포넌트에서 state를 조작할 수 있게 된다.




component에 사용하기


increase : 숫자를 1 증가시킨다.

increase by 5 : 숫자를 5 증가시킨다.

decrement : 숫자를 1 감소시킨다.

Toggle Counter : 숫자가 보이는 부분을 감춘다.





src/counter.js

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

const Counter = () => {

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

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

  const increaseHandler = () =>{
    dispatch({type:"increase", amount : 5}) //amount가 변경되면 증감하는 값도 변경됨
  }

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

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

export default Counter;

위 화면을 만드는 컴포넌트 코드이다. 하나하나씩 살펴보자

css에 대한 기록이 아니기 때문에 그부분은 넘어가도록 하겠다.




import { useSelector, useDispatch } from "react-redux";
  • useSeletor : store에서 내가 가져오고 싶은 값을 골라 가져올 수 있다.
  • useDispatch : 등록한 counterReducer에 action을 주기 위해서는 useDispatch훅을 사용해 명령을 전달한다. 사용방법을 바로 확인해보자




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

우선 값을 가져오기 위해 useSelector를 사용하는 모습을 볼 수 있다. state를 사용해서 값의 일부를 가져왔다. useSeletor를 사용하는 순간 해당 컴포넌트는 자동으로 store에 구독이 된다. 즉 useSeletor로 인해 가져온값에 변화가 생긴다면 컴포넌트가 재 랜더링 된다는 말이다.

또 useDispatch()로 action을 내려줄 준비를 마쳤다.




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

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

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

dispatch에 type이라는 값을 내려주어서 Reducer에 있는 명령어를 실행시킬 수 있다. 또 action에 내가 변경시키고 싶은 값이 있다면 amout같이 증가 시켜줄 값을 임의로 설정할 수 있다. useState같은 hook을 사용하면 동적으로 변경할 수 있을 것이다.




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

이제 불로온 값들을 화면에 출력할 수 있다.




참고강의 : https://www.udemy.com/course/best-react/

profile
frontend developer

0개의 댓글