1) 2가지 형태로 나뉜다
2) 액션이 스토어에 전달되면, 'store에 있는 상태를 변경하는 용도'로 사용된다
3) 액션 생성자 (Action Creator)
4) 액션이 동작하는 방식
1) Action -> useSelector(state) -> Reducer 함수 -> Store -> 컴포넌트
2) Action -> dispatch(액션생성자함수) -> Reducer 함수 -> Store -> 컴포넌트
3) 원본을 훼손하면 X, 전후비교로 업데이트가 된다.
1) createStore(rootReducer)
2) combineReducers({})
1) store.getState()
2) store.dispatch(액션)
3) store.subscribe(이벤트)
4) replaceReducer(다음 리듀서)
1) useSelector(state)
2) useDispatch()
1) action 파일
// src/store/actions/actions.js (action 파일)
// 액션 객체 (액션 타입 + 액션 생성자 함수)
// 4번)
export const INCREMENT = 'INCREMENT'; // 1번)
export function addAction(call) { // 2번)
return { // 3번)
type: INCREMENT, // type
call // payload
}
}
export const DECREMENT = 'DECREMENT';
export function subAction(call) {
return {
type: DECREMENT,
call
}
}
export const RESET = 'RESET';
export function resetAction(call) {
return {
type: RESET,
call
}
}
export const PUSH = 'PUSH';
export function pushAction(call) {
return {
type: PUSH,
call
}
}
[ 주석 설명 ]
1. 액션의 type을 정의한다. (일반적으로, 액션의 type은 대문자 + _ 조합을 사용)
2. 액션을 생성하는 함수를 만든다. (액션 생성자)
3. 액션 객체를 return (항상 객체 형태로 return을 작성해야한다)
4. export 해주면, reducer에서 사용가능
2) 개별 reducer 파일
// src/store/reducers/addsub.js (reducer 파일 1)
import { INCREMENT, DECREMENT, RESET } from './actions' // 4번)
// 초기값 설정
const initialState = { // 3번)
value: 0
}
// 리듀서 함수
export default function addsubReducer(state = initialState, action) { // 1번)
if (action.type === INCREMENT) {
console.info(action.call); // 6번)
return { ...state, value: state.value + 1 } // 2번)
} else if (action.type === DECREMENT) {
return { ...state, value: state.value - 1 }
} else if (action.type === RESET) {
return { ...state, value: 0 }
}
return state // 5번)
}
[ 주석 설명 ]
1. 1번째 인자는 현재state, 2번째 인자는 액션객체
2. 업데이트 할 새로운state (원본을 훼손하면 안되기때문에, 객체복사를 사용)
3. 초기값 설정 (undefined 방지) // 이 값이 화면에 출력되는 초기값!!!
4. -
5. 꼭 넣어야한다 (undefined 방지) // 이 값이 화면에 출력되는 초기값!!!
6. payload 사용
// src/store/reducers/count.js (reducer 파일 2)
import { PUSH } from './actions' // 4번)
// 초기값 설정
const initialState = { // 3번)
count: 0
}
// 리듀서 함수 (if ver)
export default function countReducer(state = initialState, action) { // 1번)
if (action.type === PUSH) {
return { ...state, count: state.count + 1 } // 2번)
}
return state // 5번)
}
// 리듀서 함수 (switch ver): if문 or switch 중에 원하는 것 사용하면 된다 (취향차이)
// export default function countReducer(state = initialState, action) {
// switch (action.type) {
// case PUSH: {
// return {...state, count: state.count + 1}
// }
// default:
// return state
// }
// }
[ 주석 설명 ]
1. 1번째 인자는 현재state, 2번째 인자는 액션객체
2. 업데이트 할 새로운state (원본을 훼손하면 안되기때문에, 객체복사를 사용)
3. 초기값 설정 (undefined 방지) // 이 값이 화면에 출력되는 초기값!!!
4. -
5. 꼭 넣어야한다 (undefined 방지) // 이 값이 화면에 출력되는 초기값!!!
3) 통합 reducer 파일
// src/store/reducers/index.js (reducer 파일 통합)
import { combineReducers } from 'redux'; // 1번)
import addsubReducer from './addsub'
import countReducer from './count'
// 방법 1)
const rootReducer = combineReducers({ // 2번)
value: addsubReducer, // const { value } = useSelector(state => state.value)
count: countReducer // const { count } = useSelector(state => state.count)
})
// 방법 2)
// const rootReducer = combineReducers({
// addsubReducer, // const { value } = useSelector(state => state.addsubReducer)
// countReducer // const { count } = useSelector(state => state.countReducer)
// })
export default rootReducer; // 3번)
[ 주석 설명 ]
1. combineReducers
2. 리듀서 함수들 통합
3. 내보내기
4) createStore 파일
// src/store/store.js
import { createStore } from 'redux'; // 1번)
import rootReducer from './reducers'; // 2번)
const store = createStore(rootReducer) // 3번)
export default store; // 4번)
[ 주석 설명 ]
1. 반드시 필요
2. reducer 통합함수를 가져온다
3. reducer 함수를 등록
4. 콘솔에 store를 찍으면,
// getState: ƒ getState()
// dispatch: ƒ dispatch(action)
// subscribe: ƒ subscribe(listener)
// replaceReducer: ƒ replaceReducer(nextReducer)
5) redux 사용 컴포넌트
// src/App.js (redux 사용, 컴포넌트 1)
import React from 'react';
import { useSelector, useDispatch } from "react-redux"; // 1번)
import { addAction, subAction, resetAction, pushAction } from './store/actions' // 4번)
function App() {
const dispatch = useDispatch() // 2번)
// 3번)
const { value } = useSelector(state => state.value) // addsubReducer // 처음 렌더링 될때는 초기값이 출력된다
const { count } = useSelector(state => state.count) // countReducer
const addButton = () => {
dispatch(addAction(`action.type === 'INCREMENT' 인 경우`)) // 5번)
}
const subButton = () => {
dispatch(subAction())
}
const resetButton = () => {
dispatch(resetAction())
}
const pushButton = () => {
dispatch(pushAction())
}
return (
<div className="App">
<div>
value: { value }
</div>
<button onClick={ addButton }> + </button>
<button onClick={ subButton }> - </button>
<button onClick={ resetButton }> reset </button>
<div>
count: { count }
</div>
<button onClick={ pushButton }> click </button>
</div>
);
}
export default App;
[ 주석 설명 ]
1. -
2. 꼭 할당해서 사용해야한다
3. state가 rootReducer // 상태가 객체이고 구조분해할당
4. 액션 생성자 함수를 불러온다
5. reducer함수(액션생성자(payload))
6) index 파일
// scr/main.jsx (Vite 버전)
// scr/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { Provider } from 'react-redux'; // store를 사용하기 위해서 필요한 단계 1
import store from './store/store' // store.js (./폴더명/파일명)
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={ store }> // store를 사용하기 위해서 필요한 단계 2
<App />
</Provider>
</React.StrictMode>
);
1) action 파일
// src/store/actions/actions.js (action 파일)
// 액션 객체 (액션 타입 + 액션 생성자 함수)
// 4번)
export const INCREMENT = 'INCREMENT'; // 1번)
export function addAction(call) { // 2번)
return { // 3번)
type: INCREMENT, // type
call // payload
}
}
export const DECREMENT = 'DECREMENT';
export function subAction(call) {
return {
type: DECREMENT,
call
}
}
export const RESET = 'RESET';
export function resetAction(call) {
return {
type: RESET,
call
}
}
export const PUSH = 'PUSH';
export function pushAction(call) {
return {
type: PUSH,
call
}
}
[ 주석 설명 ]
1. 액션의 type을 정의한다. (일반적으로, 액션의 type은 대문자 + _ 조합을 사용)
2. 액션을 생성하는 함수를 만든다. (액션 생성자)
3. 액션 객체를 return (항상 객체 형태로 return을 작성해야한다)
4. export 해주면, reducer에서 사용가능
2) 개별 reducer 파일
// src/store/reducers/addsub.js (reducer 파일 1)
import { INCREMENT, DECREMENT, RESET } from './actions' // 4번)
// 초기값 설정
const initialState = 0; // 3번)
// 리듀서 함수
export default function addsubReducer(state = initialState, action) { // 1번)
if (action.type === INCREMENT) {
console.log(action.call); // 6번)
return state + 1 // 2번)
} else if (action.type === DECREMENT) {
return state - 1
} else if (action.type === RESET) {
return state * 0
}
return state // 5번)
}
[ 주석 설명 ]
1. 1번째 인자는 현재state, 2번째 인자는 액션객체
2. 업데이트 할 새로운state
3. 초기값 설정 (undefined 방지) // 이 값이 화면에 출력되는 초기값!!!
4. -
5. 꼭 넣어야한다 (undefined 방지) // 이 값이 화면에 출력되는 초기값!!!
6. payload 사용
// src/store/reducers/count.js (reducer 파일 2)
import { PUSH } from './actions' // 4번)
// 초기값 설정
const initialState = 0; // 3번)
// 리듀서 함수
export default function countReducer(state = initialState, action) { // 1번)
if (action.type === PUSH) {
return state + 1 // 2번)
}
return state // 5번)
}
[ 주석 설명 ]
1. 1번째 인자는 현재state, 2번째 인자는 액션객체
2. 업데이트 할 새로운state
3. 초기값 설정 (undefined 방지) // 이 값이 화면에 출력되는 초기값!!!
4. -
5. 꼭 넣어야한다 (undefined 방지) // 이 값이 화면에 출력되는 초기값!!!
3) 통합 reducer 파일
// src/store/reducers/index.js (reducer 파일 통합)
import { combineReducers } from 'redux'; // 1번)
import addsubReducer from './addsub'
import countReducer from './count'
// 방법 1)
const rootReducer = combineReducers({ // 2번)
value: addsubReducer, // const value = useSelector(state => state.value)
count: countReducer // const count = useSelector(state => state.count)
})
// 방법 2)
// const rootReducer = combineReducers({
// addsubReducer, // const value = useSelector(state => state.addsubReducer)
// countReducer // const count = useSelector(state => state.countReducer)
// })
export default rootReducer; // 3번)
[ 주석 설명 ]
1. combineReducers
2. 리듀서 함수들 통합
3. 내보내기
4) createStore 파일
// src/store/store.js
import { createStore } from 'redux'; // 1번)
import rootReducer from './reducers'; // 2번)
const store = createStore(rootReducer) // 3번)
export default store; // 4번)
[ 주석 설명 ]
1. 반드시 필요
2. reducer 통합함수를 가져온다
3. reducer 함수를 등록
4. 콘솔에 store를 찍으면,
// getState: ƒ getState()
// dispatch: ƒ dispatch(action)
// subscribe: ƒ subscribe(listener)
// replaceReducer: ƒ replaceReducer(nextReducer)
5) redux 사용 컴포넌트
// src/App.js (redux 사용, 컴포넌트 1)
import React from 'react';
import { useSelector, useDispatch } from "react-redux"; // 1번)
import { addAction, subAction, resetAction, pushAction } from './store/actions' // 4번)
function App() {
const dispatch = useDispatch() // 2번)
// 3번)
const value = useSelector(state => state.value) // addsubReducer // 처음 렌더링 될때는 초기값이 출력된다
const count = useSelector(state => state.count) // countReducer
const addButton = () => {
dispatch(addAction(`action.type === 'INCREMENT' 인 경우`)) // 5번)
}
const subButton = () => {
dispatch(subAction())
}
const resetButton = () => {
dispatch(resetAction())
}
const pushButton = () => {
dispatch(pushAction())
}
return (
<div className="App">
<div>
value: { value }
</div>
<button onClick={ addButton }> + </button>
<button onClick={ subButton }> - </button>
<button onClick={ resetButton }> reset </button>
<div>
count: { count }
</div>
<button onClick={ pushButton }> click </button>
</div>
);
}
export default App;
[ 주석 설명 ]
1. -
2. 꼭 할당해서 사용해야한다
3. state가 rootReducer
4. 액션 생성자 함수를 불러온다
5. reducer함수(액션생성자(payload))
6) index 파일
// scr/main.jsx (Vite 버전)
// scr/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { Provider } from 'react-redux'; // store를 사용하기 위해서 필요한 단계 1
import store from './store/store' // store.js (./폴더명/파일명)
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={ store }> // store를 사용하기 위해서 필요한 단계 2
<App />
</Provider>
</React.StrictMode>
);