<react-redux>
Provider
: react app 전체에 제공할 store를 주입하는 장소useSelector
: store를 가져오는 역할 (state)useDispatch
: action을 reducer로 보내는 역할 (setState)하나의 자바스크립트 파일안에 액션 타입(Actions), 액션 생성 함수(Action Creators), 리듀서(Reducer)가 모두 들어있게 작성하는 패턴.
<규칙>
src/index.js
import ReactDOM from "react-dom";
import { createStore } from "redux";
import { Provider } from "react-redux";
import App from "./App";
import rootReducer from "./redux";
const store = createStore(rootReducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
src/redux/index.js
import { combineReducers } from "redux";
import counter from "./counter";
import modal from "./modal";
import users from "./users";
const rootReducer = combineReducers({
counter,
todos,
users
});
export default rootReducer;
src/redux/counter.js
// 기능1
// Action Type
const INCREASE = "counter/INCREASE";
const DECREASE = "counter/DECREASE";
// 덕스 패턴에서는 액션 타입을 정의할 때 이와 같이 접두사를 붙임.
// 다른 모듈과 이름이 중복되지 않게 하기 위함.
// Action Creator & Action
export const increase = () => ({ type: INCREASE });
export const decrease = () => ({ type: DECREASE });
// 모듈의 초기상태
const initialState = { count: 0 };
// Reducer
export default function counter(state = initialState, action) {
switch (action.type) {
case INCREASE:
return { count: state.count + 1 };
case DECREASE:
return { count: state.count - 1 };
default:
return state;
}
}
src/redux/todos.js
// 기능2
/* ----------------- 액션 타입 ------------------ */
const ADD_TODO = 'todos/ADD_TODO';
const TOGGLE_TODO = 'todos/TOGGLE_TODO';
/* ----------------- 액션 생성 함수 ------------------ */
let nextId = 1;
export const addTodo = text => ({
type: ADD_TODO,
todo: {
id: nextId++,
text
},
});
export const toggleTodo = id => ({
type: TOGGLE_TODO,
id,
});
/* ----------------- 모듈의 초기 상태 ------------------ */
const initialState = []; // todo list
// 아래와 같은 객체가 상태(배열)에 추가될 예정
/**
{
id: 1,
text: '청소하기',
done: false,
}
*/
/* ----------------- 리듀서 ------------------ */
export default function todos(state = initialState, action) {
switch (action.type) {
case ADD_TODO:
return state.concat(action.todo);
case TOGGLE_TODO:
return state.map(todo =>
todo.id === action.id ? { ...todo, done: !todo.done } : todo
);
default:
return state;
}
}
src/App.js
import { useDispatch, useSelector } from "react-redux";
import { increase, decrease } from "./redux/counter";
export default function App() {
const counter = useSelector((store) => store.counter);
const dispatch = useDispatch();
const onIncrease = () => {
dispatch(increase());
};
const onDecrease = () => {
dispatch(decrease());
};
return (
<div className="App">
<h1>Hello Redux</h1>
<p>{counter.count}</p>
<button onClick={onIncrease}>+</button>
<button onClick={onDecrease}>-</button>
</div>
);
}