본문 바로가기

블록체인_9기/🩵 React

49강_230710_React(Redux)

728x90

 

 

 

 


Redux

  • Redux는 리액트에서 사용할 수 있는 JS 상태관리 라이브러리이다.
    • React는 자식 컴포넌트에 props로 전달받은 값을 사용하기 때문에, 자식관계가 아닌 컴포넌트와는 데이터를 직접 공유하는 것이 불가능하다.
    • 따라서, 공유해야할 데이터를 공유받는 자식 컴포넌트들이 사용할 때 공통적인 부모라는 개념인 store를 만드는 것이다.
      • store로 데이터를 공유할 수 있도록 만들어 준 것이다.
      • 리엑트의 데이터 흐름은 단방향이라 이런 단점을 보완하기 위해 만들어졌다.
    • 데이터를 직접 부모에게 전달받는 것이 아닌, 컴포넌트에 직접 값을 요청하고 전달받는 것을 말한다.
  • Action, Dispatch, Store가 연계해 동작하는 패턴이다.

 

Action

  • store에 전달할 데이터를 지칭한다.
  • 액션을 사용해서 스토어에 데이터를 보내게 된다.
  • 액션은 자바스크립트 객체 형식으로 만들어져 있다.
  • dispatch 함수를 사용해서 매개변수로 액션을 전달하면 reducer가 호출되면서 매개변수로 액션을 받게된다.
    • dispatch(action)을 수행하면 리듀서가 호출되면서 리듀서에 액션을 전달하게 된다.

 

Reducers

  • dispatch함수를 통해 액션을 리듀서 함수에 전달한다.
  • 리듀서 함수는 매개변수로 전달받은 액션을 확인하고 스토어에 상태를 업데이트할지 여부를 결정한다.
  • reducer는 반환된 값을 비교하는게 아니라 주소값을 비교하기 때문에 값이 변하는게 아닌, 주소가 바뀌어야 업데이트가 진행된다.
    • 반환되는 값은 항상 다른 주소값을 지니도록 해야한다.

 

Store

  • 상태가 관리되는 오직 하나의 공간이다.
  • 컴포넌트와 별개로 store라는 공간이 있어, 필요한 상태 값을 담아둔다.
  • 특정 컴포넌트에서 전역 상태 값이 필요할 때, store에 접근해서 데이터를 가져온다.
  • store에 있는 데이터를 변수에 값을 넣는 것처럼 바로 바꿀 순 없고, 함수를 사용해서 값을 전달할 수 있다.

 

Redux의 동작구조

컴포넌트(View / UI) 👉 useDispatch 👉 Action 👉 Reducer 👉 store

  • 컴포넌트가 useDispatch함수를 사용해서 Action을 보내고 Reducer가 전달 받고 값을 업데이트할지 여부를 체크한 뒤 store의 값을 최신화 시켜준다.
  • Action은 동작할 기능, 이름, 행동등을 의미한다.(ex. 주문서)
  • reducer 함수를 실행해서 내가 동작을 기능을 조건문으로 작성해준 파일(ex. 메뉴판)
  • store 컴포넌트가 어떤 Action을 실행시킬지 Reducer함수로 받고 store의 값을 최신화 시켜준다.
  • store의 값이 바뀌면 전역상태를 가져오고 있는 컴포넌트들은 리렌더링 된다.

 

Redux 설치

설치명령어

// 리덕스 설치
npm install redux

//리엑트에서 리덕스 사용할 수 있도록
npm install react-redux

 

 

 

 


Redux DevTools

  • 구글 확장 프로그램이다.
  • 전역 상태를 개발하면서 브라우저의 개발자모드로 전역 상태가 바뀌는것을 실시간으로 확인할 수 있다.
  • VS Code 터미널에 redux-devtools-extension 을 설치한다.
npm install redux-devtools-extension

 


Redux를 사용한 간단한 예시

#. 폴더의 경로는 다음과 같다.

1. redux/reducer/index.js_store로 설정할 객체를 선언하고, 스토어 상태를 변경하는 함수 reducer를 선언한다.

  • 객체 init을 선언하여 상태값으로 사용할 값을 키값 형태로 넣어준다.
  • reducer함수를 선언하여 전달받은 action의 값에 따라 반환되는 값을 넣어준다.
// store 값 설정
let init = {
  count: 0,
  isLogin: false,
  userState: {
    userName: "",
    userAge: 1,
    ;
  },
};

// 예) 주문 받으면 action이 음식 이름
function reducer(state = init, action) {
  console.log(action);
  // 음식이 뭔지 조건문
  switch (action.type) {
    case "김치볶음밥":
      // 반환값이 무조건 있어야 하기 때문에 break가 아닌 return이 들어가야 한다.
      // 리듀서 함수의 반환값으로 저장소를 최신화시켜준다.
      // 저장소는 대기하다가 리듀서가 호출되면 값을 반환받아서 최신화 시켜준다.
      return { ...state, count: state.count + 1 };
    case "계란볶음밥":
      return { ...state, count: state.count - 1 };
    case "LOGIN":
      // ...state : 초개 객체의 값을 복사
      /*   count: 0,
        isLogin: false,
        userState: {
          userName: "",
          userAge: 1,
        },*/
      // + isLogin : true
      /*   count: 0,
        isLogin: true,
        userState: {
          userName: "",
          userAge: 1,
        },*/

      return { ...state, isLogin: action.payload };
    case "LOGOUT":
      return { ...state, isLogin: action.payload };
    default:
      return { ...state };
  }
}

export default reducer;

 

2. redux/store.js_createStore함수로 store를 생성한다.

  • createStore: Redux store를 생성하는 함수이다.
    • 첫 번째 매개변수로 reducer 함수를 받는다.
      • reducer함수에는 store와 action을 받아 다음 상태로 반환하는 함수이다.
  • composeWithDevTools: store의 전역상태가 변화하는 것을 크롬 브라우저의 개발자모드에서 확인가능한 도구확장 프로그램 툴이다.
    • 개발자모드 (F12) => Redux 탭을 클릭하면 확인 가능하다.
import { createStore } from "redux";
import reducer from "./reducer";
import { composeWithDevTools } from "redux-devtools-extension";


let store = createStore(reducer, composeWithDevTools());

export default store;

 


🤷 createStore에 취소선이 그어진 이유는?

RTK(Redux Tookit)를 사용하는 것을 권장하기 때문이다.

  • redux 공식문서에는 RTK 사용을 권장하고 있기 때문에 취소선이 그어져 있다.
  • 하지만 createStore API를 제거하지 않을것이기 때문에 그대로 사용해도 무방하다.
  • 취소선이 보고 싶지 않다면, RTK를 사용하거나, 하단의 코드로 사용하면 취소선 없이 사용이 가능하다.
import {legacy_createStore as createStore} from 'redux'


 

 

3. index.js_Provider 컴포넌트를 통해 자식 컴포넌트에 store를 주입해준다.

import { Provider } from "react-redux";
import store from "./redux/store";

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

reportWebVitals();

 

4. App.js_전체 화면에 그려질 컴포넌트를 넣어준다.

  • Count 컴포넌트 : '김치볶음밥', '계란볶음밥' 버튼이 있어, 해당 버튼을 누르면 count의 수가 올라가거나 내려간다.
  • Count2 컴포넌트 : payload로 boolean 값을 주어서 login / logout 버튼에 따라 isLogin값이 ture, false로 변한다.
  • CountView 컴포넌트 : store에 저장되어 있는 count값을 render한다.
import "./App.css";
import { Count, CountView, Count2 } from "./components";

function App() {
  return (
    <div className="App">
      <Count></Count>
      <Count2></Count2>
      <CountView></CountView>
    </div>
  );
}

export default App;

 

5. components/Count.js_useDispatch를 이용해서 각 버튼마다 동작시킬 행동의 이름을 지정한다.

  • useDispatch : action을 보낼 수 있는 함수이다.
  • 매개변수의 객체를 통해 action을 진행한다.
    • type : 동작시킬 행동의 이름
    • payload : (option) 상태를 변경할 때 데이터 전달이 필요하면 사용된다.
import React from "react";
import { useDispatch } from "react-redux";

const Count = () => {
  const dispatch = useDispatch();

  const handlerAdd = () => {
    dispatch({ type: "김치볶음밥" });
  };
  const HandlerRemove = () => {
    dispatch({ type: "계란볶음밥" });
  };
  return (
    <div>
      <button onClick={handlerAdd}>김치볶음밥</button>
      <button onClick={HandlerRemove}>계란볶음밥</button>
    </div>
  );
};

export default Count;

 

6. components/Count2.js_useDispatch를 이용해서 각 버튼마다 동작시킬 행동의 이름을 지정한다.(payload 사용)

import React from "react";
import { useDispatch } from "react-redux";

const Count2 = () => {
  const dispatch = useDispatch();

  // 상태패턴 관리할 때 대문자로 쓰자!
  // 플레이어가 걷기, 달리기, 점프 상태 등의 네이밍을 대문자로 통일해야한다.
  // RUN, STATE, JUMP
  
  const handlerAdd = () => {
    dispatch({ type: "LOGIN", payload: true });
  };
  const HandlerRemove = () => {
    dispatch({ type: "LOGOUT", payload: false });
  };
  return (
    <div>
      <button onClick={handlerAdd}>로그인</button>
      <button onClick={HandlerRemove}>로그아웃</button>
    </div>
  );
};

export default Count2;

 

7. components/CountView.js_useSelector를 이용해서 render시킬 저장소의 값을 불러온다.

  • useSelector : 전역 상태 값을 조회할 때 사용한다.
    • 전역으로 관리되고 있는 상태의 값을 컴포넌트가 직접 접근해서 가져온다.
import React from "react";
import { useSelector } from "react-redux";

const CountView2 = () => {
  // 저장소 값을 가져와보자
  // react Hook 함수. react-redux라이브러리에서 제공
  
  // 상태에서 count를 반환
  // count가 변경되었을 때 리렌더링 된다.
  // count 값을 상태로 보고있다.
  const count = useSelector((state) => state.count);
  return <div>{count}</div>;
};

export default CountView2;

 

 

 

 

728x90