⚛︎ Redux

zooyaho·2022년 8월 22일
0
post-thumbnail

⚛️ Redux

  • 리덕스는 크로스 컴포넌트 상태, 앱와이드 상태를 위한 상태 관리 시스템이다.
  • 일반적인 프로그래밍 개념으로 리듀서 함수는 입력을 변환해서 새로운 출력, 새로운 결과를 뱉어내는 기능을 수행한다.
  1. 로컬상태 : 데이터가 변경되어서 하나의 컴포넌트에 속하는 UI에 영향을 미치는 상태를 말한다.
  2. 크로스 컴포넌트 상태 : 모달 오버레이 컴포넌트는 다수의 컴포넌트에서 사용하게 되는데, 이때 모달을 닫는 트리거는 모달 컴포넌트에서 여는 트리거는 다수의 컴포넌트에서 관리를 하게 된다. 이런 경우와 같이, 다수의 컴포넌트가 협력하여 상태관리를 하는 상태를 말한다.
  3. 앱와이드 상태 : 애플리케이션의 모든 컴포넌트에 영향을 미치는 상태를 말한다. 예를들어 로그인 상태에 따른 UI변경

● flux 아키텍쳐

  • facebook에서 고안한 어플리케이션 아키텍쳐
  • flux아키텍쳐의 가장 큰 특징: 단방향 데이터 흐름

● React Context의 잠재적 단점

  • 리액트 컨텍스트를 사용하면 설정과 상태관리가 복잡해질 수 있다.
  • 데이터가 자주 변경되는 경우 성능 저하의 원인이 될 수 있다.

● Redux 작동 방식

  • Redux = Reducer + Flux : flux 아키텍쳐에 reducer라는 개념을 도입
  • 모든 전역 state를 하나의 거대한 object에 모두 담음
  • 하나의 중앙 데이터 저장소, 전체 어플리케이션의 모든 상태를 저장함.
  • 중앙 데이터 저장소에 구독을 하여 데이터를 사용한다.
  • 절대로 저장된 데이터를 직접 조작하지 않으며, 데이터 변경(update)은 변형을 담당하는 리듀서 함수를 설정하여 사용한다.
  • 컴포넌트가 액션을 발송하여 그에 따른 리듀서함수를 실행(트리거)한다.

📎 설치

npm install redux : redux는 react와 연관없는 패키지이다.
npm install react-redux : redux와 react앱의 작업을 쉽게 하기위해 해당 패키지 설치.

  • 리덕스 스토어에 컴포넌트를 서브스크라이브라고 한다.

✔️ Reducer 함수

  • 리듀서 함수는 리덕스 라이브러리에 의해 호출이 됨.
  • 항상 새로운 상태 객체를 리턴해야 함.
  • 리듀서 함수는 순수한 함수여야함. 여기서 순수한 함수란 리덕스가 제공하는 입력을 취하고 예상된 출력물인 새로운 상태 객체를 생성해야 한다.
  • 함수 안에서는 어떠한 부수적인 효과가 없어야 하는데, 예를들어 HTTP요청을 전송한다거나 뭔가를 로컬 저장소에 기록한다거나 로컬 저장소에서 뭔가를 가져오지 말아야 함.

✔️ 메서드

  • subscribe() : 인자로 구독자 함수를(저장소를 사용하는 컴포넌트) 취함. 리덕스는 데이터와 저장소가 변경될 때마다 인자로 받은 함수(구독자 함수)를 실행시킴.
  • getState() : createStore()로 생성된 저장소에서 사용 가능한 메서드, 업데이트된 저장소 데이터를 반환함.
  • dispatch() : 액션을 발송하는 메소드, 액션은 객체타입
    💡 action을 dispatch하면 리듀서 함수에서 해당 type의 조건문이 없어도 리듀서 함수는 실행된다!!
  • createStore(리듀서 함수) : Store생성 메서드

✔️ 예제

👾 redux-demo.js

// js에서 서드파티패키지를 inport하는 방법
const redux = require("redux");

const counterReducer = (state = { counter: 0 }, action) => {
  if (action.type === "increment") {
    return {
      counter: state.counter + 1,
    };
  }
  if (action.type === "decrement") {
    return {
      counter: state.counter - 1,
    };
  }
  // 초기값 state 반환
  return state;
};

const store = redux.createStore(counterReducer);

/* 구독자 컴포넌트 */
const counterSubscriber = () => {
  // 저장소에 있는 업데이트된 데이터 반환
  const latestState = store.getState();
  console.log(latestState);
};

// subscribe()메서드는 인자로 counterSubscriber함수를 취함.
// 리덕스는 데이터와 저장소가 변경될 때마다 인자로 받은 함수(구독자 함수)를 실행시킴.
store.subscribe(counterSubscriber);

// dispatch()는 액션을 발송하는 메소드, 액션은 객체타입
// 💡 action을 dispatch하면 리듀서 함수에서 해당 type의 조건문이 없어도 리듀서 함수는 실행된다!!
store.dispatch({ type: "increment" });
store.dispatch({ type: "decrement" });

💡 파라미터 state에 초기값을 설정하는 이유

  • 저장소를 초기화할 때 리덕스가 리듀서함수를 실행시키기 때문에 state에 보조 기본값(=초기값)을 지정해야 함.

💡 파라미터로 함수의 포인터를 전달하는 이유는 리듀서와 구독함수를 모두 리덕스가 실행하기 때문

● React에서 Redux사용하기

💡 react-redux Hooks

  • useSelector : 자동으로 스토어가 관리하는 상태의 일부를 선택하게 해줌.(= 자동 구독 설정)
    • useSelector(state => state.counter) : 인수로 리덕스가 관리하는 상태를 받으며 상태의 일부를 반환함. 콜백함수는 리액트 리덕스에 의해 실행이 됨!
  • useStore : 저장소의 인스턴스를 반환합니다. 이것을 사용하는 구성 요소가 업데이트되지 않기 때문에 일반적으로 권장되지 않음. 이러한 경우 useEffect와 같은 반응 후크를 사용하여 명시적으로 구성 요소를 업데이트해야 함!
  • connect : 함수형 컴포넌트에서 래퍼로 사용, 클래스 컴포넌트 근처에서 클래스 컴포넌트를 스토어에 연결
  • useDispatch : 인수로 아무것도 전달하지 않고, 실행할 수 있는 dispatch function을 반환함. Redux store에 대한 action을 보냄.

✔️ 예제

1️⃣ store생성

👾 store/index.js

import { createStore } from "redux";

const counterReducer = (state = { counter: 0 }, action) => {
  if (action.type === "increment") {
    return { counter: state.counter + 1 };
  }
  if (action.type === "decrement") {
    return { counter: state.counter - 1 };
  }
  return state;
};

const store = createStore(counterReducer);

export default store;

2️⃣ 공급자 생성하여 리덕스에 접근 가능한 컴포넌트들의 범위 지정 - Provider

👾 index.js

import { Provider } from 'react-redux'
import counterStore from './store/index'

root.render(<Provider store={counterStore}><App /></Provider>);

👉🏻 Provider의 store프롭에 연결할 store지정
👉🏻 counterStore: 제공자 컴포넌트, store프롭에 연결함으로써 리덕스 스토어를 제공함.

3️⃣ store의 데이터 접근 - useSelector

👾 Counter.js

import { useSelector } from 'react-redux'

const Counter = () => {
  ...
  // 리액트 스토어에 자동 구독 설정
  // 스토어에 데이터가 변경될 때마다 자동으로 가장 최신의 counter를 받음.
  const counter = useSelector(state=> state.counter);
}

👉🏻 자동으로 리덕스 스토어가 바뀐다면 컴포넌트 함수가 재실행 됨!!

4️⃣ action 보내기 - useDispatch

👾 Counter.js

import { useSelector, useDispatch } from 'react-redux'

const Counter = () => {
  ...
  // 실행할 수 있는 dispatch function을 반환.
  const dispatch = useDispatch();
  // store에 있는 counter 가져옴.
  const counter = useSelector(state => state.counter);
  
  const incrementHandler = () => {
    // dispatch function을 호출하는 argument
    dispatch({type: 'increment'});
  }
  const decrementHandler = () => {
    dispatch({type: 'decrement'});
  }
}
...
return (
  <div>{counter}</div>
  <button onClick={incrementHandler}>증가 버튼</button>
  <button onClick={decrementHandler}>감소 버튼</button>
);

5️⃣ action payload 추출하기

: 버튼 클릭시 amount씩 값 증가

👾 index.js

if (action.type === "increment") {
  return { counter: state.counter + action.amount };
}

👾 Counter.js

const incrementHandler = () => {
  dispatch({type: 'increment', amount: 5 });
}

👉🏻 증가값을 유동적으로 설정 가능하다.

profile
즐겁게 개발하자 쥬야호👻

0개의 댓글