[React] Redux

rang·2022년 7월 30일

React

목록 보기
1/5
post-thumbnail

전역 상태관리 라이브러리(Global State를 의미하고 그것을 관리하게 도와주는 라이브러리)

useState를 사용시 발생하는 불편함을 해소해준다.

  • 부-모 관계가 아니여도 사용 가능하다.
  • Props Drilling 처럼 사용하지 않는 컴포넌트를 거지치 않아도 사용 가능하다.
  • 자식 컴포넌트에서 부모 컴포넌트로 값을 보낼 수 있다.

Redux Install

yarn add redux react-redux

Folder Structure

  • redux: 리덕스와 관련된 코드를 모두 모아 놓을 폴더
  • config: 리덕스 설정과 관련된 파일들을 놓을 폴더
  • configStore: store(중앙 state 관리소)를 만드는 설정 코드들이 있는 파일
  • modules: state들의 그룹
├── public
├── src
|   ├── redux
|   |   ├── config
|   |   |   └── configStore.js
|   |   ├── modules
|   |   |   ├── counter.js
|   |   |   └── todos.js
│   ├── App.js
│   ├── App.test.js
│   ├── index.css
│   ├── index.js
│   ├── reportWebVitals.js
│   └── setipTests.js
├── .gitignore
├── package.json
├── yarn.lock
└── README.md

실행 순서

모듈 만들기 → 스토어에 연결(configStore.js) → 컴포넌트에서 Store 조회, 수정, 삭제

1. 모듈 만들기 → Ducks 패턴

모듈을 밑의 순서로 작성한다.

// Action Value
    
// Action Creator
    
// Initial State
    
// Reducer
    
// export default Reducer

  • Action Value
    상수이기 때문에 항상 대문자로 선언해야 한다.
const PLUS_ONE = "PLUS_ONE";
const MINUS_ONE = "MINUS_ONE";
const ADD_NUMBER = "ADD_NUMBER";
const SUB_NUMBER = "SUB_NUMBER";
  • Action Creator - type 이란 key를 가져야 하는 객체. 리듀서로 보낼 명령
    ES6에서는 객체의 key와 value가 값으면 한 번만 작성하면 된다.
export const plusOne = () => { 
	return {
		type: PLUS_ONE,
	};
};
        
export const minusOne = () => { 
	return {
		type: MINUS_ONE,
	};
};
    
export const addNumber = (payload) => {
	return {
		type: ADD_NUMBER,
		payload,            // === payload: payload
	};
};
   
export const subNumber = (payload) => {
	return {
		type: SUB_NUMBER,
        payload,
	};
};
  • Initial State
// 초기값이 0
const initialState = 0;
        
// 초기값이 0이 있는 배열 
const initialState = [0];
        
// 초기값이 number = 0, name = 'Jane'인 객체
const initialState = {
	number: 0,
	name: 'Jane'
};
  • Reducer - 디스패치를 통해 전달받은 액션객체 검사, 일치시 변화를 만들어내는 함수
const counter = (state = initialState, action) => {
	switch(state.type) {
		case PLUS_ONE:
			return {
				number: state.number + 1;
			};
		case MINUS_ONE:
			return {
				number: state.number - 1;
			};
        	
		case ADD_NUMBER:
			return {
				number: state.number + action.payload,
			};
		case SUB_NUMBER:
			return {
				number: state.number - action.payload,
			};
        
		default:
			return state;
    }
};

Ducks 패턴

  • Reducer 함수를 export default
  • Action Creator 함수를 export
  • Action type은 app/reducer/ACTION_TYPE 형태로 작성한다.

modules/counter.js

// Action Value
const PLUS_ONE = "PLUS_ONE";
const MINUS_ONE = "MINUS_ONE";
const ADD_NUMBER = "ADD_NUMBER";
const SUB_NUMBER = "SUB_NUMBER";
    
// Action Creator
export const plusOne = () => { 
	return {
		type: PLUS_ONE,
	};
};
        
export const minusOne = () => { 
	return {
		type: MINUS_ONE,
	};
};
    
export const addNumber = (payload) => {
	return {
		type: ADD_NUMBER,
		payload,            // === payload: payload
	};
};
   
export const subNumber = (payload) => {
	return {
		type: SUB_NUMBER,
        payload,
	};
};
    
// Initial State
const initialState = {
	number: 0,
};
    
// Reducer
const counter = (state = initialState, action) => {
	switch(state.type) {
		case PLUS_ONE:
			return {
				number: state.number + 1;
			};
		case MINUS_ONE:
			return {
				number: state.number - 1;
			};
        	
		case ADD_NUMBER:
			return {
				number: state.number + action.payload,
			};
		case SUB_NUMBER:
			return {
				number: state.number - action.payload,
			};
        
		default:
			return state;
    }
};
    
// export default Reducer
export default counter;

2. 스토어(Store)에 연결하기

Module - Store 연결하기
combineReducers() 함수 안에 모듈을 작성한다.

config/configStore.js

import { createStore } from "redux";
import { combineReducers } from "redux";
    
import counter from "../modules/counter";
    
const rootReducer = combineReducers({
	counter: counter,
});
const store = createStore(rootReducer);
    
export default store;

3. 컴포넌트에서 스토어(Store) 조회하기, 수정하기

Module - Store 연결 확인

  • 컴포넌트에서 스토어 조회하기 → useSelector((state) ⇒ state)
  • 컴포넌트에서 스토어로 액션 보내기 → useDispatch({ type: “PLUS_ONE” })

App.js

import React from "react";
import { useDispatch, useSelector } from "react-redux";
    
import { addNumber, subNumber, minusOne, plusOne } from "./redux/modules/counter";
    
const App = () => {
	const [number, setNumber] = useState(0);
	const counterStore = useSelector((state) => state);
	const globalNumber = useSelector(state => state.counter.number);
	console.log(counterStore);
    
	const dispatch = useDispatch();
    
	const onChangeHandler = (evnet) => {
		const { value } = evnet.target;
		setNumber(+value);                // string to number -> +str
    };
    
	const onClickAddNumberHandler = () => {
		dispatch(addNumber(number));
	};
    
	const onClickSubNumberHandler = () => {
		dispatch(subNumber(number));
	};
    
	return (
		<div>
			<input type="number" onChange={onChangeHandler}/>
			{globalNumber}
			<button onClick={() => dispatch(plusOne)}>+1</button>
			<button onClick={() => dispatch(minusOne)}>-1</button>
			<button onClick={onClickAddNumberHandler}>더하기</button>
			<button onClick={onClickSubNumberHandler}>빼기</button>
		</div>
	);
}
    
export default App;
profile
천천히 가더라도 앞으로만 나아가자

0개의 댓글