Redux

김남경·2022년 12월 28일

react

목록 보기
16/37

데이터 흐름(flux 패턴)

UI(Action) ➡️ Dispatch ➡️ Reducer ➡️ Store(상태 변경)

✅ 단방향 패턴

원칙

💡 Single source of truth
동일한 데이터는 같은 곳에서 가져와야 한다
store라는 단 하나의 공간과 연결
💡 State is read-only
action 객체가 있어야만 상태를 변경할 수 있음
💡 Changes are made with pure functions
reducer 내의 함수는 순수함수 이어야 한다

작성

📗 Provider 적용

//index.js

import { Provider } from 'react-redux';
//Provider는 redux를 손쉽게 사용할 수 있게 하는 컴포넌트

root.render(
  //적용
  <Provider>
    <App />
  </Provider>
);

📗 createStore로 store 생성

//index.js

import { Provider } from 'react-redux';
import { legacy_createStore as createStore } from 'redux';
//import { createStore } from 'redux';

//reducer 생성
const count = 1;
const counterReducer = (state = count, action) => {
	switch(action.type){
      case 'INCREASE':
        return state + 1;
      case 'DECREASE' :
        return state - 1;
      //인자가 필요한 경우
      case 'SET_NUMBER'
        return action.payload;
      //없으면 undefined 됨
      default:
        return state;
    }
}
//reducer 연결하여 store 생성
const store = createStore(counterReducer);
//여러개일 경우
//const rootReducer = combineReducers({
//  counterReducer,
//  anyReducer,
//});

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

✅ reducer는 순수함수이어야 함

📗 Action 객체 생성

//index.js

import { Provider } from 'react-redux';
import { legacy_createStore as createStore } from 'redux';

//action 객체 생성
export const increase = () => {
	return {
    	type : 'INCREASE'	
    };
}
export const decrease = () => {
	return {
    	type : 'DECREASE'	
    };
}
//payload가 있는 경우
export const setNumber = (num) => {
	return{
    	type : 'SET_NUMBER',
      	payload: num
    }
}

const count = 1;
const counterReducer = (state = count, action) => {
	switch(action.type){
      case 'INCREASE':
        return state + 1;
      case 'DECREASE' :
        return state - 1;
      case 'SET_NUMBER'
        return action.payload;
      default:
        return state;
    }
}
const store = createStore(counterReducer);

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

📗 Dispatch 생성

//App.js

import { useDispatch } from 'react-redux';
import { increase, decrease } from './index.js';

export default function App() {
	//reducer로 action을 전달해주는 함수
  	const dispatch = useDispatch();
  	const plusNum = () => {
      	//reducer 호출
  		//dispatch( { type: 'INCREASE' } );
    	dispatch(increase());
    }
    const minusNum = () => {
    	dispatch(decrease());
    }
    
    return (
    	<div className="container">
      		<h1>{`Count: ${1}`}</h1>
      		<div>
        		<button onClick={plusNum}>+</button>
        		<button onClick={minusNum}>-</button>
      		</div>
    	</div>
    );
}

📗 useSelector 생성

//App.js

//useSelector 추가
import { useDispatch, useSelector } from 'react-redux';
import { increase, decrease } from './index.js';

export default function App() {
  	//store에 저장된 state에 접근
  	const state = useSelector((state) => state);
  
  	const dispatch = useDispatch();
  	const plusNum = () => {
    	dispatch(increase());
    }
    const minusNum = () => {
    	dispatch(decrease());
    }
    
    return (
    	<div className="container">
        	//적용
      		<h1>{`Count: ${state}`}</h1>
      		<div>
        		<button onClick={plusNum}>+</button>
        		<button onClick={minusNum}>-</button>
      		</div>
    	</div>
    );
}

파일 나누기

📗 Provider

//index.js

import { Provider } from 'react-redux';
import { store } from './Store';

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

📗 store 생성

//Store/index.js

import { legacy_createStore as createStore } from 'redux';
import { counterReducer } from '../Reducers';

export const store = createStore(counterReducer);

📗 Reducers

//Reducers/initialState.js

export const initialState = 1;
//Reducers/index.js

import { initialState } from './initialState.js';
import { INCREASE, DECREASE } from '../Actions';

export const counterReducer = (state = initialState, action) => {
  switch (action.type) {
    case INCREASE:
      return state + 1;
    case DECREASE:
      return state - 1;
    default:
      return state;
  }
};

📗 Actions

//Actions/index.js

export const INCREASE = 'INCREASE';
export const DECREASE = 'DECREASE';

export const increase = () => {
  return {
    type: INCREASE,
  };
};
export const decrease = () => {
  return {
    type: DECREASE,
  };
};

📗 Dispatch

//App.js

import { useSelector, useDispatch } from 'react-redux';
import { increase, decrease } from './Actions';

export default function App() {
  const dispatch = useDispatch();
  const state = useSelector((state) => state);

  const plusNum = () => {
    dispatch(increase());
  };
  const minusNum = () => {
    dispatch(decrease());
  };

  return (
    <div className="container">
      <h1>{`Count: ${state}`}</h1>
      <div>
        <button onClick={plusNum}>+</button>
        <button onClick={minusNum}>-</button>
      </div>
    </div>
  );
}

참고

React Redux Tutorial for Beginners
In-Depth Overview
코드스테이츠 교과서

profile
기본에 충실하며 앞으로 발전하는

0개의 댓글