今天继续 todo app part2, 会纪录实作上遇到的问题。
若有错误,欢迎留言指教,感恩的心。
新增 src/components/todos/TodoItem.tsx
//@file: src/components/todos/TodoItem.tsx
import styled from "styled-components";
//定义Props介面,todo 需符合Todo的形状
interface Props {
todo: Todo; //已在types.d.ts 全域定义
index: number;
onToggleTodo: ToggleTodo;
onDeleteTodo: DeleteTodo;
}
//定义completed的style, 定义completed回传值会是boolean型别,如果是true则划线, false的话none
const StyledTodo = styled.span<{ completed: boolean }>`
text-decoration: ${(props) => (props.completed ? "line-through" : "none")};
`;
//React.FC<Props> 定义这个 FunctionComponent为Props泛型
const TodoItem: React.FC<Props> = ({
index,
todo,
onToggleTodo,
onDeleteTodo,
}) => {
return (
<div className="form-check border border-bottom-secondary rounded py-3 m-0 d-flex justify-content-between align-items-center">
<div>
<input
className=" ms-1 me-3 form-check-input"
type="checkbox"
checked={todo.complete}
onClick={() => {
onToggleTodo && onToggleTodo(index);
}}
/>
<StyledTodo className="todo" completed={todo.complete}>
{todo.text}
</StyledTodo>
</div>
<button
className="btn btn-outline-danger me-3"
onClick={() => onDeleteTodo && onDeleteTodo(index)}
>
X
</button>
</div>
);
};
export default TodoItem;
我遇到的一些事:
React.FC<>的在TypeScript使用的一个泛型,FC就是FunctionComponent的缩写,是函式组件。
React.FC<Props>
React.FC会依照Props定义好的属性型别带入参数,有点像平时我们写function带入参数的概念一样。
觉得TS 真的蛮严谨, 像 StyledTodo
, 原本是想直接带入直接使用 props.completed
, 但会报错, 他需要去定义styled.span<{ completed: boolean }>
传入值是boolean型别。
然後是说我太久没用bootstrap, v5 原本的 mr
(margin-right), 改为 me
(margin-end),right 改为e
(end),left 则改为 s
(start)。
新增 src/components/todos/AddTodoInput.tsx
//@file: src/components/todos/AddTodoInput.tsx
import React, { FormEvent, useState } from "react";
interface Props {
onCreate: IAddTodo;
}
const AddTodoInput: React.FC<Props> = ({ onCreate }) => {
const [text, setText] = useState("");
const handleSubmit = (e: FormEvent) => {
e.preventDefault();
onCreate && onCreate(text);
setText("");
};
return (
<form className="input-group mb-5" onSubmit={handleSubmit}>
<input
className="form-control border-primary"
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
/>
<button
className="btn btn-primary"
type="submit"
onClick={handleSubmit}
disabled={!text}
>
Add Todo
</button>
</form>
);
};
export default AddTodoInput;
我遇到的一些事:
onCreate
也需要标记型别, callback function 也需要定义型别。handleSubmit
需要本来以为直接用e
就可以了, 结果不行, 需定义 event 类型,可参考 React’s Event System,我这边使用的 onSubmit
属於 FormEvent,所以针对e
去定义。这个event分类比我想像中的多, 突然觉得 JS 好幸福写e
就好惹。新增 src/pages/Home.tsx
//@file: src/pages/Home.tsx
import { useState } from "react";
import AddTodoInput from "../components/todos/AddTodoInput";
import TodoItem from "../components/todos/TodoItem";
import { v4 as uuid } from "uuid";
const initialTodos: Todo[] = [
{
text: "walk the dog",
complete: true,
},
{
text: "learn TypeScript",
complete: false,
},
];
const Home = () => {
const [todos, setTodos] = useState(initialTodos);
const addTodo: AddTodo = (text: string) => {
const newTodo = { text, complete: false };
setTodos([...todos, newTodo]);
};
const toggleTodo: ToggleTodo = (index: number) => {
const newTodos: Todo[] = [...todos];
newTodos[index].complete = !newTodos[index].complete;
setTodos(newTodos);
};
const deleteTodo: DeleteTodo = (index: number) => {
setTodos([...todos.slice(0, index), ...todos.slice(index + 1)]);
};
return (
<main className="pt-5 mx-auto">
<div className="container">
<AddTodoInput onAddTodo={addTodo} />
{todos.map((todo, index) => {
return (
<TodoItem
todo={todo}
key={uuid()}
index={index}
onToggleTodo={toggleTodo}
onDeleteTodo={deleteTodo}
/>
);
})}
</div>
</main>
);
};
export default Home;
我遇到的一些事:
Todo[]
型别。AddTodo
ToggleTodo
DeleteTodo
可在 types.d.ts 定义好,比起在 function 里面定义更乾净。这边也记得改一下:
import Home from "./pages/Home";
const App = () => {
return <Home />;
};
export default App;
这就完成简单的 Todo App 了, 也同步在 github 可参考。
day29 done. 明天最後一天了~~有点感动!!!
https://typeofnan.dev/your-first-react-typescript-project-todo-app/
<<: IT 铁人赛 k8s 入门30天 -- day30 Share Process Namespace between Containers in a Pod
1.将要遮罩的Shape>Pre compose 2.最後就是最简单的部分,找张图用遮罩就完成...
执行 Google Docs 转换 API Blueprint 格式专案程序,最後来看看转换後的 ...
那麽最一开始学一个程序语言的起手式想必不用我多说吧。 「Hello World!」 fn hello...
昨晚睡一睡突然一个念头闪过, 为什麽用那麽多try catch 昨天写的程序中,我用了大量的try ...
今天念 重新认识 Vue.js | Kuro Hsu 2-2 元件之间的沟通传递 在 HTML 里的...