* Redux
: 크로스 컴포넌트 또는 앱 와이드 상태를 위한 상태 관리 시스템
상태를 변경하고 화면에 표시해주는 데이터를 관리해준다.
1. Local state(로컬상태)
데이터가 변경되어서 하나의 컴포넌트에 속하는 UI에 영향을 미치는 상태
ex) 사용자 입력을 받아와서 useState를 사용해서 그 입력을 모든 키 입력과 함께 state 변수에 저장
ex) 세부 정보 필드를 켜고 끄는 토글 버튼
>> 보통 useState 사용. 컴포넌트 내에서 로컬 상태 관리. 혹은 useReducer사용(복잡하면)
2. Cross-Component State(로컬보다 조금 더 복잡)
하나의 컴포넌트가 아니라 다수의 컴포넌트에 영향을 미치는 상태
ex) 모달 오버레이 열거나 닫는 버튼 있으면, 그 모달 컴포넌트는 다수의 컴포넌트에 영향을 미칠 수 있음
ex) 모달을 여는 트리거는 모달의 바깥에 존재, 모달 안쪽에 있는 버튼으로 모달 없앨 수 있음
>> useState 나 useReducer 이용해서 구현 가능. props넣어줘야해서 props 체인 발생.
3. App-Wide State
다수의 컴포넌트가 아니라 어플리케이션 전체에 영향을 미치는 상태
ex) 로그인 상태
>> useState, useReducer 사용. 상태값 넣어서 사용.
+) Context와 Redux의 차이
결국 Context와 Redux는 같은 기능을 하는데, 왜 Redux를 사용해야 하는 걸까?
>> 하나만 사용해야한다 X / Contex와 Redux가 사용되는 곳이 다르다 O = Redux는 Context의 대안.
- React Context의 단점(잠재적이기 때문에 상황에 따라 사용자가 선택하면 된다.)
1) 설정이 복잡해질 수 있고, 리액트 컨텍스트를 이용한 상태 관리가 복잡해질 수 있다.
>> 소형~중형 프로젝트에서는 상관X
>> 심하게 중첩된 JSX코드와 다양하고 많은 ContextProvider, 코드를 다 떄려박은 커다란 하나의 ContextPovider
2) 데이터가 자주 바뀌는 경우에는 성능문제가 발생할 수 있다.
Redux는 데이터(상태)가 보관되어 있는 중앙데이터저장소(무조건 하나의 저장소만 가진다)
- 컴포넌트가 저장소를 구독하고, 데이터가 변경될 때 마다 저장소가 컴포넌트에 알려준다. 컴포넌트는 필요한 데이터를 받게 된다.(ex. 현재의 인증상태) 리덕스 저장소의 일부를 받아 사용할 수 있다.
리덕스 내부에 있는 데이터는 상태이기 때문에, 때때로 변경된다.
변경된 상태는 업데이트 되어야 하는데, 어떻게 할까?
컴포넌트는 절대 리덕스에 저장된 데이터를 직접 조작하지 않는다.
리듀서 함수를 사용해서 저장소 데이터를 변경한다(Mutate)
+) useReducer() != Reducer
+) useReducer() ▶ 훅 / Reducer ▶ 리덕스도 사용
리듀서 함수는 입력을 받아서 그 입력을 변환하고 축소하는 함수
ex) 숫자로 된 리스트를 숫자들의 합으로 줄일 수 있음
액션들을 리듀서로 전달해서, 액션이 원하는 것을 리듀서가 하게 된다.
npm init -y
리덕스를 설치하기 위해 서드파티 패키지 설치해야한다.
npm install redux
install 하게 되면 node_modules에 redux와 종속파일 생성된다.
node.js로 실행할거기 때문에 impor가 기존 react 파일과 다르다.
const redux = require("redux");
//저장소를 만들어야 한다.
//리듀서 함수를 만들어야 한다.
//액션과 컴포넌트도 필요하다.
//저장소를 구독하기 위한 설정코드도 필요하다.
const conuterReducer = () => {};
const store = redux.createStore();
** reducer함수는 표준 자바스크립트 함수지만, 리덕스 라이브러리에 의해 호출된다.
항상 2개의 입력(2개의 파라미터)을 받는다.
기존의 상태 + 발송된 액션 => 상태 객체 리턴
같은 input 이 들어가면 같은 output이 나와야 하기 때문에 순수한 자바스크립트 함수여야 한다.
ex) http 요청 전송, 로컬스토리지에 저장 혹은 가져오면 안됨.
리덕스가 제공하는 입력을 통해 예상한 새로운 상태 객체를 생성
npm install redux react-redux
리덕스는 리액트에서만 사용하는 것이 아니기 때문에 react-redux 패키지도 설치해줘야한다.
이 패키지가 리액트 앱과 리덕스 스토어와 리듀서에 쉽게 접근할 수 있게 해준다.
- state 조회하기 위한 useSelector 사용가능
- action 발생시키기 위한 useDispatch 사용가능
import { useSelector, useDispatch } from "react-redux";
//useSelector: 저장소가 관리하는 상태 부분을 자동으로 선택할 수 있다.
import classes from "./Counter.module.css";
const Counter = () => {
//어떤 인자도 전달하지 않고 대신 실행할 수 있는 dispatch function
//redux store에 대한 action을 보낸다.
const dispatch = useDispatch();
//저장소에서 추출하려는 데이터 부분 결정
const counter = useSelector((state) => state.counter);
const show = useSelector((state) => state.showCounter);
const increaseHandler = () => {
dispatch({
type: "increase",
amount: 5,
});
};
const incrementHandler = () => {
dispatch({ type: "increment" });
};
const decrementHandler = () => {
dispatch({ type: "decrement" });
};
//toggle로 숨기고 보여지게 하는 것은 useState사용해서 관리해야한다.
//왜냐믄요 이 컴포넌트에서만 쓰는거니까요...!(local state)
const toggleCounterHandler = () => {
dispatch({ type: "toggle" });
};
return (
<main className={classes.counter}>
<h1>Redux Counter</h1>
{show && <div className={classes.value}>{counter}</div>}
<div>
<button onClick={incrementHandler}>Increment</button>
<button onClick={increaseHandler}>Increase by 5</button>
<button onClick={decrementHandler}>Decrement</button>
</div>
<button onClick={toggleCounterHandler}>Toggle Counter</button>
</main>
);
};
export default Counter;
import { createStore } from 'redux';
const counterReducer = (state = { counter:0 }, action) => {
if(action.type === "increase"){
return{
counter: state.counter + action.amount,
};
}
if(action.type === "decrement"){
return{
counter: state.counter - action.amount,
};
}
};
const store = createStore(counterReducer);
export default store;
//index.js
아마 이게 제일 이해하기 쉬울걸요? React + Redux 플로우의 이해
https://qiita.com/mpyw/items/a816c6380219b1d5a3bf?utm_campaign=popular_items&utm_medium=feed&utm_source=popular_items 를 번역한 문서입니다.
medium.com
위의 redux 코드의 경우 프로젝트의 규모가 작을 때에는 문제가 되지 않지만, 규모가 커지게 되면 문제가 발생한다.
1. 다수의 개발자들이 개발을 함께 하다보면 액션이 많아지면서 "식별자"에 오타가 생기거나, 겹치는 식별자가 생기게 되는데 심지어는 식별자들끼리 충돌을 일으킬수도있다.
>> 식별자들을 한 번에 정리해놓고, 그 다음부터 정의된 이름을 사용하면 좋을 것 같다.
>> 상수를 생성해 식별자를 정의한 뒤, 그 식별자를 내보낸다.
export const INCREMENT = 'increment';
>> counter.js 컴포넌트에서 export한 상수를 사용할 수 있다.
import { INCREMENT } from '../store/index';
>> 대신 상수를 사용하려면 import 해야한다.
2. 가지고 있는 데이터와 상태가 많을수록 상태 객체가 점점 커지면서 상태를 계속 복사해주고 reducer함수의 길이가 길어질 수 있다.(모든 것들을 redux 파일에 넣어서)
'Frontend·Client > React' 카테고리의 다른 글
[React] 리덕스 툴킷 (0) | 2023.02.06 |
---|---|
[React] Redux toolkit (0) | 2023.02.01 |
React Hook 규칙, Forward Refs, useImperativeHandle(focus와 scroll) (0) | 2023.01.29 |
[React] sh: react-scripts: command not found에러 (0) | 2023.01.29 |
[React] useReducer() (0) | 2023.01.27 |