module > todos.js
sss
//1)액션타입을 정의해주고(대문자,스네이프케이스, string을 할당해주면 끝)
//2)액션함수를 만들어주고
// (근데, 함수는 export 해주고, 넘겨야할 인자 있으면,
//넘겨주고, 바디 객체안에도 인자를 같이 써주고)
//(근데, let nextId 처럼 변수는 export 위에 써주고)
//(근데 addTodo 안에 type 과 todo 키가 있네.. )
//3)초기값 객체로 설정해주고,
//4)리듀서 함수는 export default로.
// if(action.type=== 액션변수) 이런식으로 써주고
//바디는 return 필수
//+ 글을 추가해줄때는 : state.concate(새로운 객체)
//+ 특정부분 다른스타일 : state.map( todo=> ? {} :todo)
const ADD_TODO = "todos/ADD_TODO";
const TOGGLE_TODO = "todos/TOGGLE_TODO";
let nextId = 2;
export const addTodo = (text) => ({
type: ADD_TODO,
todo: { id: nextId++, text },
});
export const toggleTodo = (id) => ({
type: TOGGLE_TODO,
id,
});
const initialState = [
{
id: 1,
text: "리덕스공부",
done: true,
},
];
export default function todos(state = initialState, action) {
if (action.type === ADD_TODO) {
return state.concat(action.todo);
}
if (action.type === TOGGLE_TODO) {
return state.map((todo) =>
todo.id === action.id ? { ...todo, done: !todo.done } : todo
);
}
return state;
}
//확인해보려는 코드 (아래)
// const store = createStore(todos);
// console.log(store.getState());
모듈 리듀서를 합쳐주는 combineReducers
module > index.js
import { combineReducers } from "redux"
import todos from "./todos"
import counter from "./counter"
const rootReducer =combineReducers({
todos,
counter,
})
export default rootReducer
(컨테이너 컴포넌트 - 프레젠테이셔널 컴포넌트)
container > TodosContainer.js
컨테이너 컴포넌트 작성
//값을 조회하기 위해 useSelector와 디스패치하기 위해 useDispatch를 씀
// 값을 쫙 보여줘야 하니까, todos리듀서에서 빼오는건가?
// 디스패치 안에 타입과 기타를 가진 객체를 지닌 함수가 있는 거..
// return해주는건, reducer함수(todos)와 함수 2개..
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import Todos from "../components/Todos";
import { addTodo, toggleTodo } from "../module/todos";
const TodosContainer = () => {
const todos = useSelector((state) => state.todos);
const dispatch = useDispatch();
const onToggle = (id) => dispatch(toggleTodo(id));
const onCreate = (text) => dispatch(addTodo(text));
return (
<div>
<Todos todos={todos} onToggle={onToggle} onCreate={onCreate} />
</div>
);
};
export default TodosContainer;
components > Todos.js
프레젠테이셔널 컴포넌트 작성
//아이템도, 리스트도, 전체도 다 ontoggle이 필요하네
// todo는 개별 아이템에서만 나머지는 todos가 필요하네..
// 할일 지우는건, item 단에서 style&onClick으로 처리하는 군아..
//map 돌릴때 id넣는거 잊지말긔..
// 하위를 중간컴포넌트에 넣을때, 하위가 가졌던 프롭스 다 넣어주기?
//
import React, { useState } from "react";
const TodoItem = ({ todo, onToggle }) => {
return (
<li
style={{
textDecoration: todo.done ? "line-through" : "none",
backgroundColor: todo.done ? "pink" : "white",
}}
onClick={() => onToggle(todo.id)}
>
{todo.text}
</li>
);
};
const TodoList = ({ todos, onToggle }) => {
return (
<ul>
{todos.map((todo) => (
<TodoItem onToggle={onToggle} todo={todo} key={todo.id} />
))}
</ul>
);
};
const Todos = ({ todos, onCreate, onToggle }) => {
const [text, setText] = useState("");
const onChange = (e) => {
setText(e.target.value);
};
const onSubmit = (e) => {
e.preventDefault();
onCreate(text);
setText("");
};
return (
<>
<form onSubmit={onSubmit}>
<input value={text} onChange={onChange} placeholder="입력하세요" />
<button type="submit">등록</button>
</form>
<TodoList todos={todos} onToggle={onToggle} />
</>
);
};
export default Todos;