react实现todolist | 前端青训营实践

96 阅读2分钟

功能说明

通过react实现一个简易版的todolist案例 功能如下

  • 添加待办事项
  • 删除待办事项
  • 反转待办事项状态
  • 统计分类 (即筛选 已办 未办 全部

image.png

步骤实现

  1. 创建项目
npx create-next-app@latest

简单配置一下 使用typescript

目录结构如下

image.png

  1. 代码

新建组件

image.png

四个组件搭建好基本结构如下

//TodoList

function TodoList () {
    return (
        <div>
            <h1>AddTodo</h1>
        </div>
    );
}

export default TodoList;


//TodoItem

function TodoItem (prop: any) {
    return (
        <div>
            {prop.todo.title}
        </div>
    );
}

export default TodoItem;


//TodoFilter

function TodoFilter() {
  return (
    <div>
      <button>All</button>
      <button>Active</button>
      <button>Completed</button>
    </div>
  );
}

export default TodoFilter;

//AddTodo

function AddTodo () {
    return (
        <div>
            <h1>AddTodo</h1>
        </div>
    );
}

export default AddTodo;

页面组件中引入这四个初始化好的数组

import AddTodo from "./components/AddTodo";
import TodoList from "./components/TodoList";
import TodoFilter from "./components/TodoFilter";
import { useState } from "react";

export default function Home() {
  return (
    <div>
      <h1>TodoList</h1>
      <AddTodo />
      <TodoList />
      <TodoFilter />
    </div>
  );
}

定义待办的数据属性 每个待办应该有内容 id 以及是否完成的状态

在src下新建type.ts并导出

export interface Todo {
    id: number;
    text: string;
    completed: boolean;
}

引入Todo类型并使用对应的状态

image.png

添加功能及对应实现

 const addTodo = (text: string) => {
    const newTodo = {
      id: Date.now(),
      text,
      completed: false,
    };
    setTodos([...todos, newTodo]);
  }

删除功能及对应实现

  const deleteTodo = (id: number) => {
    setTodos(todos.filter(todo => todo.id !== id));
  }

切换功能及对应实现

  const toggleTodo = (id: number) => {
    setTodos(todos.map(todo => {
      if (todo.id === id) {
        return {
          ...todo,
          completed: !todo.completed,
        };
      }
      return todo;
    }));
  }

筛选功能

要添加一个标记状态

const [filter, setFilter] = useState<string>('all');

filter方法

const getFilteredTodos = () => {
    switch (filter) {
      case 'completed':
        return todos.filter(todo => todo.completed);
      case 'active':
        return todos.filter(todo => !todo.completed);
      default:
        return todos;
    }
  }

实现位置

image.png

完整的添加功能代码

import React, { useState } from 'react';

interface addTodoProps {
    addTodo: (text: string) => void;
}

function AddTodo ({addTodo} : addTodoProps) {
    const [text, setText] = useState<string>('');

    const handleSubmit = (e: React.FormEvent) => {
        e.preventDefault();
        if (!text.trim()) return;
        addTodo(text);
        setText('');
    }
    return (
       <form onSubmit={handleSubmit}>
              <input
               type="text"
                value={text}
                onChange={(e) => setText(e.target.value)}
               />
              <button>Add</button>
       </form>
    );
}

export default AddTodo;

Todolist完整代码 主要有todo 删除和反转 接受从page传过来的props 定义一个interface来接收

import { Todo } from "../type"; 
import TodoItem from "./TodoItem";
interface TodoListProps {
    todos: Array<Todo>;
    deleteTodo: (id: string) => void;
    toggleTodo: (id: string) => void;
}

function TodoList ({todos, deleteTodo, toggleTodo} : TodoListProps) {
    return (
       <ul>
           {todos.map(todo => (
               <TodoItem key={todo.id} todo={todo} deleteTodo={deleteTodo} toggleTodo={toggleTodo} />
            ))}
       </ul>
    );
}

export default TodoList;

接收完成后再传入TodoItem组件里

TodoItem的完整代码

接收props, 定义点击的实现函数

import {Todo} from '../type';

interface TodoItemProps {
    todo: Todo;
    deleteTodo: (id: string) => void;
    toggleTodo: (id: string) => void;
}


function TodoItem ({todo, deleteTodo, toggleTodo} : TodoItemProps) {
    return (
        <li style={{textDecoration: todo.completed ? 'line-through' : 'none'}}>
            {todo.text}
            <button onClick={() => toggleTodo(todo.id)}>Toggle</button>
            <button onClick={() => deleteTodo(todo.id)}>Delete</button>
        </li>
    );
}

export default TodoItem;

现在只差TodoFilter啦

筛选只需要改变filter的值 filter的值一改变 对应的返回给todolist的todos数组就会改变 从而页面就会改变

interface TodoFilterProps {
    setFilter: (filter: string) => void;
}


function TodoFilter({setFilter} : TodoFilterProps) {
  return (
    <div>
      <button onClick={() => setFilter('all')}>All</button>
      <button onClick={() => setFilter('completed')}>Completed</button>
      <button onClick={() => setFilter('active')}>Active</button>
    </div>
  );
}

export default TodoFilter;

总结

总体来说自己react+ts这么来写很熟练, 实现的功能非常简单没有写样式,朴实无华版,中间有一些报错主要是ts类型的错误,用ts一方面会有这种类型错误,一方面因为类型提示很好找这个错误.总而言之写这个小demo还是有所收获的