image.png

0. React typescript中组件的导入、导出形式

0.1 导入形式

  1. import { TodoList } from './components/TodoList';

0.2 导出形式

  1. export const TodoList: React.FC<IProps> = (props) => {
  2. return (
  3. <ul>
  4. ...
  5. </ul>
  6. );
  7. };

1. 根目录新建types.d.ts文件

把所有的类型定义写在这里,在其他文件中使用类型时不需要导入,因为ts编译器会自动去这个文件里找类型

types.d.ts【类型统一开头大写】

  1. type Todo = {
  2. text: string;
  3. complete: boolean;
  4. };
  5. type ToggleTodo = (selectedTodo: Todo) => void;
  6. type AddTodo = (newTodo: string) => void;

2. e的类型

handleSubmit = (e) => {};我们经常会碰到要填写e的类型,在不同情境下e的类型不同

2.1 input框onChange监听时

e的类型是ChangeEvent

  1. <input type="text" value={newTodo} onChange={handleChange} />
  2. const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
  3. setNewTodo(e.target.value);
  4. };

2.2 form表单onSubmit提交时

e的类型是FormEvent

  1. <button type="submit" onClick={handleSubmit}>
  2. Add Todo
  3. </button>
  4. const handleSubmit = (e: FormEvent<HTMLButtonElement>) => {
  5. e.preventDefault();
  6. addTodo(newTodo);
  7. setNewTodo('');
  8. };

3. useState更新state时的写法

3.1 state简单类型

  1. const [newTodo, setNewTodo] = useState<string>('');
  2. const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
  3. setNewTodo(e.target.value);
  4. };

3.2 state是个数组

选中的那项, state中该项的complete改变, true => false, false => true

  1. const [todos, setTodos] = useState(initalState);
  2. const toggleTodo: ToggleTodo = (selectedTodo) => {
  3. const newTodos = todos.map((todo) => {
  4. if (todo === selectedTodo) {
  5. return {
  6. ...todo,
  7. complete: !todo.complete,
  8. };
  9. }
  10. return todo;
  11. });
  12. setTodos(newTodos);
  13. };

新增一个todo对象到todos数组中

  1. const addTodo: addTodo = (newTodo) => {
  2. setTodos([
  3. ...todos, // 把已有的todos展开
  4. { // 新的todo(类型是对象)
  5. text: newTodo,
  6. complete: false,
  7. },
  8. ]);
  9. };

4. 完整代码

4.1 App.tsx

  1. import React, { Fragment, useState } from 'react';
  2. import { TodoList } from './components/TodoList';
  3. import { AddTodoForm } from './components/AddTodoForm';
  4. const initalState: Todo[] = [
  5. {
  6. text: 'Walk the dog',
  7. complete: true,
  8. },
  9. {
  10. text: 'Write app',
  11. complete: false,
  12. },
  13. ];
  14. const App: React.FC = () => {
  15. const [todos, setTodos] = useState(initalState);
  16. const toggleTodo: ToggleTodo = (selectedTodo) => {
  17. const newTodos = todos.map((todo) => {
  18. if (todo === selectedTodo) {
  19. return {
  20. ...todo,
  21. complete: !todo.complete,
  22. };
  23. }
  24. return todo;
  25. });
  26. setTodos(newTodos);
  27. };
  28. const addTodo: AddTodo = (newTodo) => {
  29. newTodo.trim() !== '' &&
  30. setTodos([
  31. ...todos,
  32. {
  33. text: newTodo,
  34. complete: false,
  35. },
  36. ]);
  37. };
  38. return (
  39. <Fragment>
  40. <TodoList todos={todos} toggleTodo={toggleTodo} />
  41. <AddTodoForm addTodo={addTodo} />
  42. </Fragment>
  43. );
  44. };
  45. export default App;

4.2 TodoList.tsx

  1. import React from 'react';
  2. import { TodoListItem } from './TodoListItem';
  3. interface IProps {
  4. todos: Todo[];
  5. toggleTodo: ToggleTodo;
  6. }
  7. export const TodoList: React.FC<IProps> = ({ todos, toggleTodo }) => {
  8. return (
  9. <ul>
  10. {todos.map((todo) => {
  11. return (
  12. <TodoListItem key={todo.text} todo={todo} toggleTodo={toggleTodo} />
  13. );
  14. })}
  15. </ul>
  16. );
  17. };

4.3 TodoListItem.tsx

  1. import React from 'react';
  2. import './TodoListItem.css';
  3. interface IProps {
  4. todo: Todo;
  5. toggleTodo: ToggleTodo;
  6. }
  7. export const TodoListItem: React.FC<IProps> = ({ todo, toggleTodo }) => {
  8. return (
  9. <li>
  10. <label className={todo.complete ? 'complete' : undefined}>
  11. <input
  12. type="checkbox"
  13. checked={todo.complete}
  14. onChange={() => toggleTodo(todo)}
  15. />
  16. {todo.text}
  17. </label>
  18. </li>
  19. );
  20. };

4.4 TodoListItem.css

  1. .complete {
  2. text-decoration: line-through;
  3. }

4.5 AddTodoForm.tsx

  1. import React, { useState, ChangeEvent, FormEvent } from 'react';
  2. interface Props {
  3. addTodo: AddTodo;
  4. }
  5. export const AddTodoForm: React.FC<Props> = ({ addTodo }) => {
  6. const [newTodo, setNewTodo] = useState<string>('');
  7. const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
  8. setNewTodo(e.target.value);
  9. };
  10. const handleSubmit = (e: FormEvent<HTMLButtonElement>) => {
  11. e.preventDefault();
  12. addTodo(newTodo);
  13. setNewTodo('');
  14. };
  15. return (
  16. <form action="">
  17. <input type="text" value={newTodo} onChange={handleChange} />
  18. <button type="submit" onClick={handleSubmit}>
  19. Add Todo
  20. </button>
  21. </form>
  22. );
  23. };