Redux
Redux
사용시 컴포넌트들을 props
없이 state
공유가능useReducer
와 비슷한 구조를 지님redux
에서는 객체를 action
객체라고 말함action
객체를 reducer
로 보내는 행위 = dispatch
Redux 설치방법
npm
npm i redux react-redux
yarn
yarn add redux react-redux
디자인 패턴?
파일구성을 어떻게 분리하고 관리를 할건지
Container Presenter 패턴
Container Presenter
패턴은 리액트 디자인 패턴 중 하나로, 기능과 UI를 컴포넌트 상으로 분리한 것
데이터를 처리하고, 받아오는 부분(기능)은 Container
컴포넌트에서 담당
데이터를 보여주는 부분(UI)은 Presenter
컴포넌트에서 담당
기존 패턴(정통적패턴)
- 폴더구성
- counter.js만들기
- constants -> counter.js
어떤action
이 필요한지 만듦 export const INC_COUNT = "INC_COUNT" export const DEC_COUNT = "DEC_COUNT"
- actions -> counter.js
action
객체를 만듦
import { INC_COUNT, DEC_COUNT } from '../constants/counter'
export function incCount(diff) {
return {
type: INC_COUNT,
payload: {diff}
}
}
export function decCount(diff) {
return {
type: DEC_COUNT,
payload: {diff}
}
}
- reducers -> counter.js
어떤action
들을case
로 넣을지 갖고오기
import { INC_COUNT, DEC_COUNT } from "../constants/counter";
//초기값설정
const initialState = {number: 0}
//state: 현재상태, action: 괄호안에 넣은 그 값
export default function counter(state= initialState, action) {
switch (action.type) {
case INC_COUNT:
return {number: state.number + action.payload.diff}
case DEC_COUNT:
return {number: state.number - action.payload.diff}
default:
return state
}
}
- store -> counter.js(index.js로 파일 이름이 지어줘도됨)
store
는 한 앱에 하나만 있는게 규칙
이제 App.js에서Provider
형태로 쓸 수 있게됨
import { legacy_createStore as createStore } from "redux";
import counter from '../reducers/counter'
const store = createStore(counter)
export default store
- App.js
import { Provider } from "react-redux";
import store from "./redux/store/counter";
function App() {
return (
<Provider store={store}>
<div>앱</div>
</Provider>
);
}
export default App;
- 폴더 생성
- components -> Counter.jsx
//데이터를 보여주는 부분(UI)
import React from 'react'
function Counter(props) {
const { number, onDecrease, onIncrease } = props
return (
<div>
<p>{number}</p>
<button onClick={onIncrease}>+2</button>
<button onClick={onDecrease}>-2</button>
</div>
)
}
export default Counter
- container -> CounterContainers.jsx
import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
import Counter from '../components/Counter'
import { incCount, decCount } from '../redux/actions/counter'
function CounterContainers() {
const dispatch = useDispatch()
const number = useSelector((state) => state.number)
const onIncrease = () => {
dispatch(incCount(2))
}
const onDecrease = () => {
dispatch(decCount(2))
}
return (
<Counter number={number} onIncrease={onIncrease} onDecrease={onDecrease} />
)
}
export default CounterContainers
- App.js
import CounterContainers from "./containers/CounterContainers";
<Provider store={store}>
<CounterContainers />
</Provider>
ducks 패턴
분리된 파일을 합쳐서 하나의 파일에다가 모든 코드를 작성하는 것
ducks 규칙
- 반드시 리듀서 함수를
default export
해야 한다. - 반드시 액션 생성 함수를
export
해야 한다. - 반드시 접두사를 붙인 형태로 액션타입을 정의해야 한다.
- (선택) 액션 타입은
UPPER_SNAKE_CASE
형태로 이름을 짓고export
할 수 있다.
ducks패턴 사용방법
- 파일구성
- modules -> counter.js
해당 파일에 constants, actions, reducers내용 넣기
// constatns폴더. 액션타입
const INC_COUNT = "INC_COUNT"
const DEC_COUNT = "DEC_COUNT"
// actions폴더. 액션 생성 함수
export function incCount(diff) {
return {
type: INC_COUNT,
payload: {diff}
}
}
export function decCount(diff) {
return {
type: DEC_COUNT,
payload: {diff}
}
}
// reducers 폴더
//초기값
const initialState = {number: 0}
// 리듀서
export default function counter(state= initialState, action) {
switch (action.type) {
case INC_COUNT:
return {number: state.number + action.payload.diff}
case DEC_COUNT:
return {number: state.number - action.payload.diff}
default:
return state
}
}
Redux Looger
redux
로 실행되는 로직에 대해 콘솔창에 기록을 남겨주는 역할담당 => 리덕스 미들웨어
(store
, action
객체 다룰때의 과정을 남겨줌)
설치
yarn
yarn add redux-logger --dev
npm
npm i redux-logger --dev
import { applyMiddleware } from "redux";
import logger from 'redux-logger'
const store = createStore(rootReducer, applyMiddleware(logger))
chrome Redux DevTools 확장프로그램 사용방법
Redux DevTools
확장프로그램 추가
import { applyMiddleware, compose, legacy_createStore as createStore } from "redux";
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(rootReducer, composeEnhancers(applyMiddleware(logger)));
검사창에서 실시간 로깅 확인가능
- modules -> index.js
//store내용 넣기
import { applyMiddleware, legacy_createStore as createStore } from "redux";
import logger from 'redux-logger'
import counter from './counter'
const store = createStore(counter)
export default store
- 만약 여러개의 리듀서가 있을경우
import { legacy_createStore as createStore } from "redux";
import counter from './counter'
import { combineReducers } from "redux";
//combine을 해줬기때문에
//state.counter -> counter 리듀서가 관리하는 상태에 접근
const rootReducer = combineReducers({
counter,
})
const store = createStore(rootReducer, applyMiddleware(logger))
export default store
- App.js
import { Provider } from "react-redux";
import CounterContainers from "./containers/CounterContainers";
import store from "./modules";
function App() {
return (
<Provider store={store}>
<CounterContainers />
</Provider>
);
}
export default App;
- containers -> CounterContainers
import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
import Counter from '../components/Counter'
import { incCount, decCount } from '../modules/counter'
function CounterContainers() {
const dispatch = useDispatch()
const number = useSelector((state) => state.number)
const onIncrease = () => {
dispatch(incCount(2))
}
const onDecrease = () => {
dispatch(decCount(2))
}
return (
<Counter number={number} onIncrease={onIncrease} onDecrease={onDecrease} />
)
}
export default CounterContainers
1, 2, 3번까지 같은방식으로 생성 후 pages
폴더 생성해서 구분하는방법pages
폴더는 components
안에 구분해 놓은파일들이 들어가는 폴더
Redux toolkit 설치방법
버전확인
"react": "^18.2.0", "react-dom": "^18.2.0" -> 두 버전이 18버전이상인지 확인npm
npm i @reduxjs/toolkit react-redux
yarn
yarn add @reduxjs/toolkit react-redux
- store.js파일생성
import { configureStore } from '@reduxjs/toolkit'
export default configureStore({
reducer: { }
})
- index.js로 이동
import { Provider } from 'react-redux';
import store from '경로'
<Provider store={store}></Provider> //Provider로 감싸기
Redux store에 state 보관하는 방법
1.
import { createSlice } from '@reduxjs/toolkit'
2.
//useState와 비슷한용도. state하나를 slice라 부름
const 작명 = createSlice({
name: 'state이름',
initialState: '값'
})
3.
export default configureStore({
reducer: {
작명 : 작명.reducer
}
})
Redux store에 state 꺼내는 방법
useSelector
store
에 저장되있는 상태를 가져오기 위한 Hook
1. `state` 꺼낼 컴포넌트로 이동
import { useSelector } from 'react-redux';
2.
const selector = useSelector((state)=>{ return state })
// { return state }state는 모든state를 말함
// 원하는 state만 출력가능
// ex) {return state.작명한이름}
console.log(selector) //store에 등록한 정보가 넘어오는걸 확인가능
Redux store에 state 변경하는 방법
useDispatch
useDispatch
는 dispatch
함수를 실행할 수 있도록 해주는 Hook
1. store.js로 이동
`state` 변경 원하는 `state`에 아래와 같은 형식으로 작성해주기
reducers: {
함수명(state) {
return 변경시켜주세요
}
}
2. export 해주기
export const { 함수명 } = state함수명.actions
3.
import { useDispatch } from 'react-redux';
import { 함수명 } from './../store';
const dispatch = useDispatch()
dispatch(state변경함수())
<button onClick={ () =>{ dispatch( 함수명() ) }}>변경하기</button>
state가 object/array일 경우 변경하는 방법
state
가 object/array일 경우 return 없이 직접 수정 가능
(그래서 값이 하나여도 object/array형태로 만들어서 사용하기도함)
initialState: { name: 'Yu', age: 20 },
reducers: {
함수명(state) {
state.name = 'Sunny'
},
함수명(state, action) {
state.age += action.payload
}
}
// 파라미터에 값을 넣어줘서 변경가능
<button onClick={ () =>{ dispatch( 함수명(10) ) }}>변경하기</button>
'프론트엔드 > React' 카테고리의 다른 글
useNavigate, NavLink, Lazy Loading (0) | 2022.08.09 |
---|---|
React router dom v6 (리액트 라우터 버전6) (0) | 2022.08.09 |