본문 바로가기
React

0707 Redux

by hyerin1201 2023. 7. 7.

이해하기 위해서 ㄴ반드시 개인적으로 리덕스 코드를 짜볼것...

 

리엑트는 컴포넌트 기반의 자바스크립트 라이브러리 언어이다.

컴포넌트간 데이터(props)를 부모 -> 자식요소로만 데이터를 전달 가능하다

-> 남발 /  형제간에 전달하려면 -> 부모 요소를 거쳐야함 

 

Redux :  Reduce 보다 광범위적으로 사용됨/ 리액트외 다른 언어에서도 사용 가능

  • 리덕스는 리액트의 라이브러리 중 하나
  • Props의 불편함을 개선하기 위해 만들어진 개념
  • 언제, 어디서든 store에 저장된 state를 가져다 사용할 수 있음
  • 단점!! 동기적 타입으로 기능을 수행 :  따라서 복수의  실행함수(리듀서)가 2개이상인 경우 먼저 실행한 실행문이 마쳐야지만 두번째 함수가 실행된다.
  • 리덕스를 비동기 타입으로 수행 : redux toolkit : redux middleware

 

리덕스 기본개념

웹브라우저의 기능 발생

- 액션으로 실행된 결과가 감

- 액션값을 리듀서에 전달 처리 및 실행.

- 값을 스토어에 보냄

- 다시 출력

 


설치 및 설정

https://ko.redux.js.org/

 

Redux - 자바스크립트 앱을 위한 예측 가능한 상태 컨테이너. | Redux

자바스크립트 앱을 위한 예측 가능한 상태 컨테이너.

ko.redux.js.org

  1. 터미널 명령어 입력 npm install redux 
  2. 리액트 리덕스 패키지 입력 (리덕스를 리액트 안에서 보다 쉽게 쓰이게끔 해주는 )  npm install react-redux

https://react-redux.js.org/introduction/getting-started

 

Getting Started with React Redux | React Redux

Introduction > Getting Started: First steps with React Redux

react-redux.js.org

*리덕스와 리액트 리덕스는 다르다

 

 


카운트 예제 짜보기

 

index.js

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

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

*모든 데이터가 출력되는 공간에 Store를 뿌려준다

-> store.js 파일 생성

 

store.js (컴포넌트가 아님, 함수임)

import { createStore } from "redux";
import reducer from "./reducer";

let store = createStore(reducer);

export default store;

 

 

 

함수의 실행은 App.js가 보낸(useDispatch 를 통해 보낸)  값을 reducer.js 받아서 실행함

App.js

import { useState } from "react";
import "./App.css";
import { useDispatch, useSelector } from "react-redux";

function App() {
  //const [count, setCount] = useState(0);
  const dispatch = useDispatch(); //변수에 함수를 할당. (리듀서에 자동으로 값이 감) 변수->함수가됨
  const count = useSelector((state) => state.count); //state값을 받아와서 state.count값을 받아옴

  const increase = () => {
    dispatch({ type: "INCREMENT" }); //리듀서에 값을 보냄
    //setCount(count + 1);
  };

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={increase}>증가!</button>
    </div>
  );
}

export default App;

또 useSelect 를 통해 reducer 가 실행한 결과값을 받아옴.

 

 

reducer.js 생성

리듀서는 2개의 인자값을 반드시 받는다.

  1. state 변수값 (초기값)
  2. 실행지침서
//reducer는 반드시 두개의 인자값을 받는다.
//state : 상태변화에 대한 초기값

let initialState = {
  count: 0,
}; //초기값을 설정 -> state에 매칭

function reducer(state = initialState, action) {
  console.log("action", action);
  // if (action.type === "INCREMENT") {
  //   return { ...state, count: state.count + 1 }; //변하지 않은 요소, 값이 바뀔 요소
  // } //무조건 리턴값이 있어야함
  switch (action.type) {
    case "INCREMENT":
      return { ...state, count: state.count + 1 };
    default: {
      return { ...state };
    }
  }
}

export default reducer;

if 문 / switch 문 사용가능 스위치를 더 많이 씀.

 


+ 추가기능 부여한 예제

Box.js 컴포넌트 생성. => 증가버튼을 눌렀을떄 박스 컴포넌트에서도 값을 같이 출력하고 싶다. 

import React from "react";
import { useSelector } from "react-redux";
// useSelector 를 통해 값을 받아온다
const Box = () => {
  let count = useSelector((state) => state.count);
  return <div>this is box {count}</div>;
};

export default Box;

 


+ 감소버튼 추가!

App.js

import { useState } from "react";
import "./App.css";
import { useDispatch, useSelector } from "react-redux";
import Box from "./Components/Box";

function App() {
  //const [count, setCount] = useState(0);
  const dispatch = useDispatch(); //변수에 함수를 할당. (리듀서에 자동으로 값이 감) 변수->함수가됨
  const count = useSelector((state) => state.count); //state값을 받아와서 state.count값을 받아옴

  const increase = () => {
    dispatch({ type: "INCREMENT" }); //리듀서에 값을 보냄
    //setCount(count + 1);
  };

  const decrease = () => {
    dispatch({ type: "DESCREMENT" });
  };

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={increase}>증가!</button>
      <button onClick={decrease}>감소</button>
      <Box />
    </div>
  );
}

export default App;

reducser.js

//reducer는 반드시 두개의 인자값을 받는다.
//state : 상태변화에 대한 초기값

let initialState = {
  count: 0,
}; //초기값을 설정 -> state에 매칭

function reducer(state = initialState, action) {
  console.log("action", action);
  // if (action.type === "INCREMENT") {
  //   return { ...state, count: state.count + 1 }; //변하지 않은 요소, 값이 바뀔 요소
  // } //무조건 리턴값이 있어야함
  switch (action.type) {
    case "INCREMENT":
      return { ...state, count: state.count + 1 };
    case "DESCREMENT":
      return { ...state, count: state.count - 1 };
    default: {
      return { ...state };
    }
  }
}

export default reducer;

 


+ 디스패치 요소 안에 타입말고 다른 요소 들어갈수 있음.

dispatch ( type, payload)

type : 필수인자값

payload: 선택적 *함수의 매개변수 **객체타입으로 값입력

 

App.js

  const increase = () => {
    dispatch({ type: "INCREMENT", paylodad: { num: 5 } }); //리듀서에 값을 보냄
    //setCount(count + 1);
  };

 

reducer.js

  switch (action.type) {
    case "INCREMENT":
      //return { ...state, count: state.count + 1 };
      return { ...state, count: state.count + action.payload.num }; // 5씩 증가하게 됨

num : 5 이기때문에 5씩 증가함.

 


+ reducer.js 의 초기값 설정도 여러개가 가능하다.

(따라서 리듀서에서 state 변수에 매칭시켜줄 초기값을 설정할때, 따로 변수를 만들어 매칭시켜주는 것.)

app.js

import { useState } from "react";
import "./App.css";
import { useDispatch, useSelector } from "react-redux";
import Box from "./Components/Box";

function App() {
  //const [count, setCount] = useState(0);
  const dispatch = useDispatch(); //변수에 함수를 할당. (리듀서에 자동으로 값이 감) 변수->함수가됨
  const count = useSelector((state) => state.count); //state값을 받아와서 state.count값을 받아옴
  const id = useSelector((state) => state.id);
  const pw = useSelector((state) => state.pw);

  const increase = () => {
    dispatch({ type: "INCREMENT", payload: { num: 5 } }); //리듀서에 값을 보냄
    //setCount(count + 1);
  };

  const decrease = () => {
    dispatch({ type: "DESCREMENT" });
  };

  const login = () => {
    dispatch({ type: "LOGIN", payload: { id: "kim", pw: "1234" } });
  };

  return (
    <div>
      <h1>
        {id}, {pw}
      </h1>
      <h1>{count}</h1>
      <button onClick={increase}>증가!</button>
      <button onClick={decrease}>감소</button>
      <button onClick={login}>로그인</button>
      <Box />
    </div>
  );
}

export default App;

 

reducer.js

//reducer는 반드시 두개의 인자값을 받는다.
//state : 상태변화에 대한 초기값

let initialState = {
  count: 0,
  id: "", // 추가
  pw: "", //추가
}; //초기값을 설정 -> state에 매칭

function reducer(state = initialState, action) {
  console.log("action", action);
  // if (action.type === "INCREMENT") {
  //   return { ...state, count: state.count + 1 }; //변하지 않은 요소, 값이 바뀔 요소
  // } //무조건 리턴값이 있어야함
  switch (action.type) {
    case "INCREMENT":
      //return { ...state, count: state.count + 1 };
      return { ...state, count: state.count + action.payload.num };
    case "DESCREMENT":
      return { ...state, count: state.count - 1 };
    case "LOGIN":
      return { ...state, id: action.payload.id, pw: action.payload.pw };
    default: {
      return { ...state };
    }
  }
}

export default reducer;