기억해야 할 것
패키지 설치
yarn add redux react-redux
폴더구조 생성
src
> redux
> config
> configStore.js
src
> redux
> modules
> todos.js
...users.js
configStore.js
import { createStore } from "redux";
import { combineReducers } from "redux";
import todos from '../modules/todos';
const rootReducer = combineReducers({ todos, });
const store = createStore(rootReducer);
export default store;
index.js
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
// 추가부분
import store from "./redux/config/configStore";
import { Provider } from "react-redux";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
//App을 Provider로 감싸주고, configStore에서 export default 한 store를 넣어줍니다.
<Provider store={store}>
<App />
</Provider>
);
reportWebVitals();
todos.js
reducer파일구조
action value
상수로 선언action creator
생성initial state
reducer
export
//action value 상수로 선언
const EDIT = "todos/EDIT";
const CHANGE_INPUT = "todos/CHANGE_INPUT";
const ADD = "todos/ADD";
const TOGGLE = "todos/TOGGLE";
const REMOVE = "todos/REMOVE";
//action creator 생성
export const edit = (input) => ({
type: EDIT,
input,
});
export const changeInput = (input) => ({ type: CHANGE_INPUT, input });
let nextId = 2;
export const add = (todo) => {
return {
type: ADD,
todo: {
id: nextId++,
title: todo.title,
text: todo.text,
done: false,
},
};
};
export const toggle = (id) => ({ type: TOGGLE, id });
export const remove = (id) => ({ type: REMOVE, id });
//initial state
const initialState = {
input: {
title: "",
text: "",
},
todos: [
{
id: 1,
title: "사자 밥주기",
text: "국내산 생닭 10마리",
done: false,
},
],
};
//reducer
const todos = (state = initialState, action) => {
switch (action.type) {
case EDIT:
return {
...state,
todos: state.todos.map((todo) =>
todo.id === action.input.id ? action.input : todo,
),
};
case CHANGE_INPUT:
return { ...state, input: action.input };
case ADD:
return { ...state, todos: state.todos.concat(action.todo) };
case TOGGLE:
return {
...state,
todos: state.todos.map((todo) =>
todo.id === action.id ? { ...todo, done: !todo.done } : todo,
),
};
case REMOVE:
return {
...state,
todos: state.todos.filter((todo) => todo.id !== action.id),
};
default:
return state;
}
};
//export
export default todos;
파일에서 store access
const dispatch = useDispatch();
-> 보내는용
const todos = useSelector(({ todos }) => todos.todos);
-> 데이터 가져오는 용
onChangeInput, onAdd
const onChangeInput = (e) => {
const { name, value } = e.target;
const updatedTodoItem = { ...todoItem, [name]: value };
dispatch(edit(updatedTodoItem));
};
//
const onAdd = useCallback(() => {
dispatch(add(input));
dispatch(changeInput({ title: "", text: "" }));
}, [dispatch, input]);
//
<>
<p>할 일:</p>
<input type="text" name="title" value={title} onChange={onChange} />
<p>설명: </p>
<input type="text" name="text" value={text} onChange={onChange} />
<button onClick={onAdd}>ADD</button>
</>
onToggle
const onToggle = useCallback((id) =>
dispatch(toggle(id)
), [dispatch]);
<div className="done" onClick={() => onToggle(id)}>
토글
</div>
onEdit
const todos = useSelector(({ todos }) => todos.todos);
const todoItem = todos.find((todo) => todo.id === Number(id));
const onChangeInput = (e) => {
const { name, value } = e.target;
const updatedTodoItem = { ...todoItem, [name]: value };
dispatch(edit(updatedTodoItem));
};
<input
className="titleEdit"
name="title"
type="text"
value={todoItem.title}
onChange={onChangeInput}
/>
<input
className="textEdit"
name="text"
type="text"
value={todoItem.text}
onChange={onChangeInput}
/>
//