노력이 좋아서
<step91>'react(redux)_ts_todoList'
zoaseo
2022. 7. 29. 14:48
2022.07.28 - [공부가 좋아서] - 'react(redux)_ts_counter'
<step90>'react(redux)_ts_counter'
1) npm create-react-app ts-redux-tutorial --template typescript npm install redux npm install react-redux npm install @types/react-redux react-redux 1. 모듈 리듀서 1) 액션타입 지정 2) 액션생성 함수..
zoaseo.tistory.com
1)
프레젠테이션 컴포넌트
TodoInsert.tsx
TodoList.tsx
TodoItem.tsx
2)
components/TodoInsert.tsx
import React, { FormEvent, useState } from 'react';
// 프롭스로 전달받을 데이터 타입을 지정
type TodoInsertProps = {
onInsert: (text: string) => void;
}
const TodoInsert = ({onInsert} : TodoInsertProps) => {
const [ value, setValue ] = useState('')
const onChange = (e:React.ChangeEvent<HTMLInputElement>) => {
setValue(e.target.value)
}
const onSubmit = (e:FormEvent) => {
e.preventDefault();
onInsert(value);
setValue("");
}
return (
<div>
<form onSubmit={onSubmit}>
<input onChange={onChange} value={value} placeholder="할 일을 입력하세요."/>
<button type="submit">등록</button>
</form>
</div>
);
};
export default TodoInsert;
components/TodoItem.tsx
import React, { CSSProperties } from 'react';
import { Todo } from '../modules/todos';
// props 타입 지정
type TodoItemProps = {
todo: Todo;
onToggle: (id: number) => void;
onRemove: (id: number) => void;
}
const TodoItem = ({todo, onToggle, onRemove}: TodoItemProps) => {
const handleToggle = () => onToggle(todo.id)
const handleRemove = () => onRemove(todo.id)
const textStyle: CSSProperties = {
textDecoration: todo.done ? 'line-through' : 'none'
}
const removeStyle: CSSProperties = {
color: 'red',
marginLeft: 8
}
return (
<li>
<span onClick={handleToggle} style={textStyle}>{todo.text}</span>
<span onClick={handleRemove} style={removeStyle}>X</span>
</li>
);
};
export default TodoItem;
components/TodoList.tsx
import React from 'react';
import { Todo } from '../modules/todos';
import TodoItem from './TodoItem';
// props 타입 지정
type TodolistProps = {
todos: Todo[];
onToggle:(id:number) => void;
onRemove:(id:number) => void;
}
const TodoList = ({todos, onToggle, onRemove}: TodolistProps) => {
if(todos.length === 0) return <div>등록한 항목이 없습니다.</div>;
return (
<ul>
{todos.map(todo=>(
<TodoItem todo={todo} onToggle={onToggle} onRemove={onRemove} key={todo.id}/>
))}
</ul>
);
};
export default TodoList;
containers/TodoApp.tsx
import React from 'react';
import { useDispatch } from 'react-redux';
import { useSelector } from 'react-redux';
import TodoInsert from '../components/TodoInsert';
import TodoList from '../components/TodoList';
import { RootState } from '../modules';
import { addTodo, removeTodo, toggleTodo } from '../modules/todos';
const TodoApp = () => {
const todos = useSelector((state: RootState) => state.todos)
const dispatch = useDispatch();
const onInsert = (text: string) => {
dispatch(addTodo(text))
}
const onToggle = (id: number) => {
dispatch(toggleTodo(id))
}
const onRemove = (id: number) => {
dispatch(removeTodo(id))
}
return (
<>
<TodoInsert onInsert={onInsert}/>
<TodoList todos={todos} onToggle={onToggle} onRemove={onRemove}/>
</>
);
};
export default TodoApp;
modules/index.ts
import { combineReducers } from "redux";
import counter from "./counter";
import todos from "./todos";
const rootReducer = combineReducers({ counter, todos });
export default rootReducer;
// 나중에 이 타입을 컨테이너 컴포넌트에서 불러와서 사용해야하므로
// 내보내줍니다.
export type RootState = ReturnType<typeof rootReducer>
App.tsx
import './App.css';
import ContainerCounter from './containers/ContainerCounter';
import TodoApp from './containers/TodoApp';
function App() {
return (
<div className="App">
<ContainerCounter/>
<TodoApp/>
</div>
);
}
export default App;