즉 , Redux에서는
Action -> Dispatch -> Reducer -> Store
순서로 데이터가단방향
으로 흐른다.
import {Provider} from 'react-redux'
Provider는 store를 손쉽게 사용할 수 있게 하는 컴포넌트이다.
root.render(
<Provider store={store}>
<App />
</Provider>
)
import { legacy_createStore as createStore } from 'redux';
const store = createStore(리듀서함수) // Reducer함수를 이런식으로 넣어준다.
Reducer는
Dispatch
에게서 전달받은Action
객체의type
값에 따라 상태를 변경시키는 함수이다.
const count = 1
// Reducer를 생성할 때에는 초기 상태를 인자로 요구함.
const counterReducer = (state = count, action) => {
// Action 객체의 type 값에 따라 분기하는 switch 조건문.
switch (action.type) {
//action === 'INCREASE'일 경우
case 'INCREASE':
return state + 1
// action === 'DECREASE'일 경우
case 'DECREASE':
return state - 1
// action === 'SET_NUM'일 경우
case 'SET_NUM':
return action.payload
// 해당 되는 경우가 없을 땐 기존 상태를 그대로 리턴
default:
return state;
}
}
// Reducer가 리턴하는 값이 새로운 상태가 됨.
이 때, Reducer는 순수함수여야 한다. 외부 요인으로 인해 기대한 값이 아닌 엉뚱한 값으로 상태가 변경되는 일이 없어야하기 때문이다.
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import { legacy_createStore as createStore } from 'redux';
const rootElement = document.getElementById('root');
const root = createRoot(rootElement);
const count = 1
const counterReducer = (state = count, action) => {
switch (action.type) {
case 'INCREASE':
return state + 1
case 'DECREASE':
return state - 1
case 'SET_NUM':
return action.payload
default:
return state;
}
}
const store = createStore(counterReducer);
root.render(
<Provider store={store}>
<App />
</Provider>
);
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
counterReducer,
anyReducer,
...
});
Action은 말 그대로 어떤 액션을 취할 것인지 정의해 놓은 객체이다.
// payload가 필요 없는 경우
{ type: 'UP' }
// payload가 필요한 경우
{ type: 'SET_NUM', payload: 2 }
// payload가 필요 없는 경우
const up = () => {
return {
type: 'UP'
}
}
// payload가 필요한 경우
const setNum = (num) => {
return {
type: 'SET_NUM',
payload: num
}
}
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import { legacy_createStore as createStore } from 'redux';
const rootElement = document.getElementById('root');
const root = createRoot(rootElement);
export const increase = () => {
return {type: 'INCREASE'}
}
export const decrease = () => {
return { type: 'DECREASE'}
}
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는 Reducer로 Action을 전달해주는 함수이다.
Dispatch의 전달인자로 Action 객체가 전달됨.
// Action 객체를 직접 작성하는 경우
dispatch( { type: 'INCREASE' } );
dispatch( { type: 'SET_NUM', payload: 2 } );
// 액션 생성자(Action Creator)를 사용하는 경우
dispatch( increase() );
dispatch( setNum(2) );
Redux Hooks는 React-Redux에서 Redux를 사용할 때 활용할 수 있는 Hooks 매서드를 제공한다.
그 중 크게useSelector()
,useDispatch()
이 두 가지의 매서드를 기억하자.
useDispatch() 는 Action 객체를 Reducer로 전달해 주는 Dispatch 함수를 반환하는 메서드이다.
위에서 Dispatch를 설명할 때 사용한 dispatch 함수도 useDispatch()를 사용해서 만든 것이다.
import { useDispatch } from 'react-redux'
const dispatch = useDispatch()
dispatch( increase() )
console.log(counter) // 2
dispatch( setNum(10) )
console.log(counter) // 10
useSelector() 는 컴포넌트와 state를 연결하여 Redux의 state에 접근할 수 있게 해주는 매서드이다.
import { useSelector } from 'react-redux'
const counter = useSelector(state => state)
console.log(counter) // 1
// index.js
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import { legacy_createStore as createStore } from 'redux';
const rootElement = document.getElementById('root');
const root = createRoot(rootElement);
export const increase = () => {
return {
type: 'INCREASE',
};
};
export const decrease = () => {
return {
type: 'DECREASE',
};
};
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>
);
// App.js
import React from 'react';
import './style.css';
// 1
import { useDispatch, useSelector } from 'react-redux';
import { increase, decrease, setNumber } from './index.js';
export default function App() {
const dispatch = useDispatch();
const state = useSelector((state) => state);
console.log(state); // 전역 상태에 있는 state를 읽음.
const plusNum = () => {
dispatch(increase());
};
const minusNum = () => {
dispatch(decrease());
};
const setNum = (num) => {
dispatch(setNumber(num))
}
return (
<div className="container">
<h1>{`Count: ${state}`}</h1>
<div>
<button className="plusBtn" onClick={plusNum}>
+
</button>
<button className="minusBtn" onClick={minusNum}>
-
</button>
</div>
<button className="minusBtn" onClick={() => {setNum(1)}}>
초기화
</button>
</div>
);
}
export const INCREASE = 'INCREASE';
export const DECREASE = 'DECREASE';
export const SET_NUMBER = 'SET_NUMBER';
export const increase = () => {
return {
type: INCREASE,
};
};
export const decrease = () => {
return {
type: DECREASE
}
}
export const setNumber = (n) => {
return {
type: SET_NUMBER,
payload: n,
}
}
import { initialState } from './initialState.js';
import { INCREASE, DECREASE, SET_NUMBER, increase, decrease } from '../Actions';
export const counterReducer = (state = initialState, action) => {
switch(action.type){
case INCREASE:
return state + 1;
case DECREASE:
return state - 1;
case SET_NUMBER:
return action.payload;
default:
return state;
}
}
export const initialState = 1;
import { legacy_createStore as createStore } from 'redux';
import { counterReducer } from '../Reducers';
export const store = createStore(counterReducer);
import React from 'react';
import './style.css';
import { useSelector, useDispatch } from 'react-redux';
import { increase, decrease, setNumber } from './Actions';
export default function App() {
const dispatch = useDispatch();
const state = useSelector((state) => state);
console.log(state);
const plusNum = () => {
dispatch(increase());
};
const minusNum = () => {
dispatch(decrease());
};
const setNum = (n) => {
dispatch(setNumber(n));
}
return (
<div className="container">
<h1>{`Count: ${state}`}</h1>
<div>
<button className="plusBtn" onClick={plusNum}>
+
</button>
<button className="minusBtn" onClick={minusNum}>
-
</button>
<button className="minusBtn" onClick={() => {
setNum(1)
}}>
초기화
</button>
</div>
</div>
);
}
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import { store } from './Store';
const rootElement = document.getElementById('root');
const root = createRoot(rootElement);
root.render(
<Provider store={store}>
<App />
</Provider>
);