Redux
A state management system for cross-component or app-wide state
- 우리가 상태, 즉 ! 우리의 애플리케이션을 변경하고 화면에 표시하는 데이터를 관리하도록 도와주는 상태 관리 라이브러리
- 우리가 데이터를 다수의 컴포넌트나 심지어 앱 전체에서 관리하도록 도와준다
- 유동적인 상태 관리 라이브러리
Redux 작동 방식
- 중앙 데이터 저장소(store)은 하나뿐이다.
- 컴포넌트는 저장소를 구독하고 변화를 감지한다.
- 변화된 데이터를 가져와서 UI에 보여준다.
- UI상 변화가 생기면 action 을 통해 reducer 순수 함수에 전달.
- 순수 함수로만 state 변경이 가능하다.
Redux 사용하기
- Redux 는 JavaScript(자바스트립트) 상태관리 라이브러리이다.
- React 에서 작업을 하기 위해서는
npm install redux react-redux
설치 해야함
store - index.js
// 리덕스 로직을 저장할 위치, 리덕스와 리액트를 연결함!
import { createStore } from 'redux';
// 식별자 오타 방지를 위해 상수 생성 후 내보내기
export const INCREMENT = 'increment';
// 초기상태 ( 보기 좋게 상수 처리 )
const initialState = { counter: 0, showCounter: true };
// 리듀서 함수
// showCounter: 토글버튼을 클릭시 counter 보여지는 여부 결정
function counterReducer(state = initialState, action) {
if (action.type === INCREMENT) {
return {
counter: state.counter + 1,
showCounter: state.showCounter,
};
}
if (action.type === 'increase') {
return {
counter: state.counter + action.amount,
showCounter: state.showCounter,
};
}
if (action.type === 'decrement') {
return {
counter: state.counter - 1,
showCounter: state.showCounter,
};
}
if (action.type === 'toggle') {
return {
counter: state.counter,
showCounter: !state.showCounter,
};
}
return state;
}
// 저장소 생성
const store = createStore(counterReducer);
export default store;
// 리덕스 스토어를 리액트에 제공을 해야한다 어떻게 ??
Counter.js
// 리액트 리덕스 팀이 만든 커스텀 훅 을 이용해서 데이터 가져오기
import { useSelector, useDispatch } from 'react-redux';
import classes from './Counter.module.css';
// 식별자 상수 받아오기
import { INCREMENT } from '../store/index';
// useSelector : 자동으로 상태의 일부를 선택하게 해준다
// 어떤 데이터를 스토어에서 추출할지 결정한다.
// 리액트 리덕스가 자동으로 서브스크립션(독자)를 설정한다.
// useState 대신 사용
// 만약 클래스형 컴포넌트면 connect 를 사용할 수 있다
// useDispatch : action을 다루는 훅!
const Counter = () => {
// Redux store에 대한 action을 보냄
const dispatch = useDispatch();
// 리액트 리덕스에 의해 실행
const counter = useSelector((state) => state.counter);
const show = useSelector((state) => state.showCounter);
const incrementHandler = () => {
dispatch({ type: INCREMENT });
};
// payload (전송되는 데이터) 연결
const increaseHandler = () => {
dispatch({ type: 'increase', amount: 5 });
};
const decrementHandler = () => {
dispatch({ type: 'decrement' });
};
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}>Increment by 5</button>
<button onClick={decrementHandler}>Decrement</button>
</div>
<button onClick={toggleCounterHandler}>Toggle Counter</button>
</main>
);
};
export default Counter;
React toolkit
- 항상 새로운 상태 스냅숏을 반환해야 한다, 초기값을 변경하면 안된다
- 애플리케이션 규모가 커질수록 문제가 발생 !
- action type
- 식별자 오타로 에러
- 관리하는 데이터의 양
- 가지고 있는 데이터와 상태가 많을수록, 상태 객체도 점점 커짐 !!
- 즉, 많은 상태를 복사해야하는 경우가 생긴다.
- 또한 그 모든 상태 속성을 유지하려면, 조건문 또는 함수가 늘어날 수 가 있다.
- 꼭 지켜줘야 하는 상태의 변경 불가성 (초기값!)
- 특히 중첩된 객체 및 배열에 있어서 복잡한 데이터를 가지고 있을 때, 중첩된 데이터를 실수로 바꾸면서 망치기 쉽다
⇒ 근데 다 알 필요 없어요!! 우리에겐 Redux toolkit 가 있거든요
- Redux toolkit : 리덕스 만든 사람이 만들었어요.
npm install @reduxjs/toolkit
설치- 설치하고 나면
package.json
에서redux
삭제 - 이미 Redux toolkit에 포함되어 있기때문
Redux toolkit 을 이용해서 Redux 를 간편 단순하게!
- toolkit을 이용해서 코드를 변경함
store - index.js // 리덕스 로직을 저장할 위치, 리덕스와 리액트를 연결함! import { createSlice, configureStore } from '@reduxjs/toolkit'; //createSlice >>> createReducer // 한번에 몇 가지를 단순화 한다
// 식별자 오타 방지를 위해 상수 생성 후 내보내기
// export const INCREMENT = 'increment';
// 초기상태 ( 보기 좋게 상수 처리 )
const initialState = { counter: 0, showCounter: true };
// 함수를 이용해서 전역 상태의 slice를 미리 만들어야 한다. (초기상태 아래에 작성)
// 초기 상태는 변하지 않으면서, 상태를 변화 시킬수 있다.
const counterSlice = createSlice({
// 상태마다 식별자가 필요함
name: 'counter',
// key: value 같아서 한번만 작성
initialState,
// reducers : 객체 혹은 맵 , 메서드를 추가한다.
reducers: {
increment(state) {
// Redux toolkit은 내부적으로 immer 이라는 다른 패키지를 사용하는데,
// 이런 코드를 감지하고 자동으로 원래 있는 상태를 복제 한다.
// 그리고 새로운 상태 객체를 생성하고 모든 상태를 변경할 수 없게 유지하고
// 우리가 변경한 상태는 변하지 않도록 오버 라이드 한다.
state.counter++;
},
decrement(state) {
state.counter--;
},
// payload 가 필요함 (추가 데이터가 필요하다)
// action 을 listen 하는 reducer를 가질 수 있다.
// action 이 추가 payload 및 데이터를 가지고 있다.
// action을 매개변수로 이용해서 리듀서 함수 및 메서드로 사용 할 수 있다.
increase(state, action) {
state.counter = state.counter + action.payload;
},
toggleCounter(state) {
state.showCounter = !state.showCounter;
},
},
});
// 저장소 생성
// configureStore : 객체를 전달한다.
// 만약 리듀서가 여러개일 경우, 객체를 설정해서 그 객체 안에 원하는 대로 속성 이름을 정하고
// key 값은 마음대로 정하고 value 값을 원하는 리듀서 함수를 설정하면 된다.
// 예시 reducer: { counter: counterSlice.reducer },
const store = configureStore({
reducer: counterSlice.reducer,
});
// 액션 메소드 액션 객체 생성을 해준다
// 리듀서 내의 이름만 같으면 알아서 자동으로 (완전 좋은데 ?)
// 내보내고 필요한 컴포넌트에서 받기만 하면 된다~ 개꿀~~
export const counterActios = counterSlice.actions;
export default store;
```js
counter.js
// 리액트 리덕스 팀이 만든 커스텀 훅 을 이용해서 데이터 가져오기
import { useSelector, useDispatch } from 'react-redux';
import { counterActios } from '../store/index';
import classes from './Counter.module.css';
// useSelector : 자동으로 상태의 일부를 선택하게 해준다
// 어떤 데이터를 스토어에서 추출할지 결정한다.
// 리액트 리덕스가 자동으로 서브스크립션(독자)를 설정한다.
// useState 대신 사용
// 만약 클래스형 컴포넌트면 connect 를 사용할 수 있다
// useDispatch : action을 다루는 훅!
const Counter = () => {
// Redux store에 대한 action을 보냄
const dispatch = useDispatch();
// 리액트 리덕스에 의해 실행
const counter = useSelector((state) => state.counter);
const show = useSelector((state) => state.showCounter);
const incrementHandler = () => {
dispatch(counterActios.increment());
};
// payload (전송되는 데이터) 연결
const increaseHandler = () => {
// { type : SOME_UNIQUE_IDENTIFIER, playload: 5 }
dispatch(counterActios.increase(5));
};
const decrementHandler = () => {
dispatch(counterActios.decrement());
};
const toggleCounterHandler = () => {
dispatch(counterActios.toggleCounter());
};
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}>Increment by 5</button>
<button onClick={decrementHandler}>Decrement</button>
</div>
<button onClick={toggleCounterHandler}>Toggle Counter</button>
</main>
);
};
export default Counter;

'개발 이야기 > Front-end' 카테고리의 다른 글
멜론 클론 코딩 챌린지 Assignment 01 (0) | 2023.03.31 |
---|---|
React 라이브러리 #5 (0) | 2023.03.30 |
React 라이브러리 #4 (0) | 2023.03.28 |
Virtual Dom (0) | 2023.03.27 |
React 공식문서로 디테일 잡기 #7 (0) | 2023.03.26 |