0. React typescript中组件的导入、导出形式
0.1 导入形式
import { TodoList } from './components/TodoList';
0.2 导出形式
export const TodoList: React.FC<IProps> = (props) => {return (<ul>...</ul>);};
1. 根目录新建types.d.ts文件
把所有的类型定义写在这里,在其他文件中使用类型时不需要导入,因为ts编译器会自动去这个文件里找类型
types.d.ts【类型统一开头大写】
type Todo = {text: string;complete: boolean;};type ToggleTodo = (selectedTodo: Todo) => void;type AddTodo = (newTodo: string) => void;
2. e的类型
handleSubmit = (e) => {};我们经常会碰到要填写e的类型,在不同情境下e的类型不同
2.1 input框onChange监听时
e的类型是ChangeEvent
<input type="text" value={newTodo} onChange={handleChange} />const handleChange = (e: ChangeEvent<HTMLInputElement>) => {setNewTodo(e.target.value);};
2.2 form表单onSubmit提交时
e的类型是FormEvent
<button type="submit" onClick={handleSubmit}>Add Todo</button>const handleSubmit = (e: FormEvent<HTMLButtonElement>) => {e.preventDefault();addTodo(newTodo);setNewTodo('');};
3. useState更新state时的写法
3.1 state简单类型
const [newTodo, setNewTodo] = useState<string>('');const handleChange = (e: ChangeEvent<HTMLInputElement>) => {setNewTodo(e.target.value);};
3.2 state是个数组
选中的那项, state中该项的complete改变, true => false, false => true
const [todos, setTodos] = useState(initalState);const toggleTodo: ToggleTodo = (selectedTodo) => {const newTodos = todos.map((todo) => {if (todo === selectedTodo) {return {...todo,complete: !todo.complete,};}return todo;});setTodos(newTodos);};
新增一个todo对象到todos数组中
const addTodo: addTodo = (newTodo) => {setTodos([...todos, // 把已有的todos展开{ // 新的todo(类型是对象)text: newTodo,complete: false,},]);};
4. 完整代码
4.1 App.tsx
import React, { Fragment, useState } from 'react';import { TodoList } from './components/TodoList';import { AddTodoForm } from './components/AddTodoForm';const initalState: Todo[] = [{text: 'Walk the dog',complete: true,},{text: 'Write app',complete: false,},];const App: React.FC = () => {const [todos, setTodos] = useState(initalState);const toggleTodo: ToggleTodo = (selectedTodo) => {const newTodos = todos.map((todo) => {if (todo === selectedTodo) {return {...todo,complete: !todo.complete,};}return todo;});setTodos(newTodos);};const addTodo: AddTodo = (newTodo) => {newTodo.trim() !== '' &&setTodos([...todos,{text: newTodo,complete: false,},]);};return (<Fragment><TodoList todos={todos} toggleTodo={toggleTodo} /><AddTodoForm addTodo={addTodo} /></Fragment>);};export default App;
4.2 TodoList.tsx
import React from 'react';import { TodoListItem } from './TodoListItem';interface IProps {todos: Todo[];toggleTodo: ToggleTodo;}export const TodoList: React.FC<IProps> = ({ todos, toggleTodo }) => {return (<ul>{todos.map((todo) => {return (<TodoListItem key={todo.text} todo={todo} toggleTodo={toggleTodo} />);})}</ul>);};
4.3 TodoListItem.tsx
import React from 'react';import './TodoListItem.css';interface IProps {todo: Todo;toggleTodo: ToggleTodo;}export const TodoListItem: React.FC<IProps> = ({ todo, toggleTodo }) => {return (<li><label className={todo.complete ? 'complete' : undefined}><inputtype="checkbox"checked={todo.complete}onChange={() => toggleTodo(todo)}/>{todo.text}</label></li>);};
4.4 TodoListItem.css
.complete {text-decoration: line-through;}
4.5 AddTodoForm.tsx
import React, { useState, ChangeEvent, FormEvent } from 'react';interface Props {addTodo: AddTodo;}export const AddTodoForm: React.FC<Props> = ({ addTodo }) => {const [newTodo, setNewTodo] = useState<string>('');const handleChange = (e: ChangeEvent<HTMLInputElement>) => {setNewTodo(e.target.value);};const handleSubmit = (e: FormEvent<HTMLButtonElement>) => {e.preventDefault();addTodo(newTodo);setNewTodo('');};return (<form action=""><input type="text" value={newTodo} onChange={handleChange} /><button type="submit" onClick={handleSubmit}>Add Todo</button></form>);};
