store folder
reducers
store - index.js
import {configureStore} from '@reduxjs/toolkit';
import reducers from '../reducers/';
const store = configureStore({
reducer: reducers,
});
console.log(store);
export default store;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
// Provider와 store import
import {Provider} from 'react-redux';
import store from './store';
ReactDOM.render(
// 최상위 컴포넌트에 Provider를 설정하고 생성한 store를 연결한다.
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
counter.js
: counter state를 증가/감소 시키는 reducer
const initialState = {counter: 0}; const counter = (state = initialState, action) => { // 절대 기존의 state를 변경해서는 안 됨. // 예측 불가능한 동작이 발생하거나, 디버깅이 어려움, // state가 동기화되지 않는 더 큰 앱에서 부작용이 발생할 수 있음. // UI가 state를 정확히 반영하지 않을 수 있음. switch (action.type) { case 'INCREMENT': return {...state, counter: state.counter + 1}; case 'DECREMENT': return {...state, counter: state.counter - 1}; case 'INCREASE': return {...state, counter: state.counter + action.amount}; default: return {...state}; } }; export default counter;
showContent.js
: 컴포넌트 동적으로 보여주기 위한 boolean state
const showContent = (state = {show: true}, action) => { switch (action.type) { case 'SHOW': return {...state, show: true}; case 'HIDE': return {...state, show: false}; default: return {...state}; } }; export default showContent;
index.js
: counter.js와 showContent.js를 합친다.
// combineReducers를 통해 분리한 reducer를 합칠 수 있고, // reducer의 이름을 따로 설정할 수도 있다. import {combineReducers} from 'redux'; import counter from './counter'; import showContent from './showContent'; const rootReducer = combineReducers({ counter, // count : counter showContent, // show : showContent }); export default rootReducer;
Counter.js
import {useSelector, useDispatch} from 'react-redux';
const Counter = () => {
const dispatch = useDispatch(); // dispatch 호출
// 관리하고 싶은 state의 일부를 return함
// useSelector를 이용하여 리덕스가 자동으로 subscription을 설정해줌.
const {counter} = useSelector((state) => state.counter);
const {show} = useSelector((state) => state.showContent);
// counter,showContent는 reducers라는 객체로 store에서 관리되기 때문에,
// 구조분해할당을 통해 state 값을 상수로 선언한다.
const incremnetHandler = () => {
dispatch({type: 'INCREMENT'});
};
const increaseHandler = () => {
dispatch({type: 'INCREASE', amount: 5});
};
const decremnetHandler = () => {
dispatch({type: 'DECREMENT'});
};
const toggleCounterHandler = () => {
show ? dispatch({type: 'HIDE'}) : dispatch({type: 'SHOW'});
};
// click event가 발생했을 때,
// dispatch를 통해 발생한 action을 reducer에 전달해주면
// reducer는 type을 읽고 설정했던 action type에 맞는 리턴값이 전달된다.
![](https://velog.velcdn.com/images/simplicityyy/post/1ab41e70-430a-4e5c-bac9-61df0c578c7c/image.gif)
return (
<main className={classes.counter}>
<h1>Redux Counter</h1>
{show && <div className={classes.value}>{counter}</div>}
<div>
<button onClick={incremnetHandler}>Increment</button>
<button onClick={increaseHandler}>Increment BY 5</button>
<button onClick={decremnetHandler}>Decrement</button>
</div>
<button onClick={toggleCounterHandler}>Toggle Counter</button>
</main>
);
};
export default Counter;