如何防止待办事项应用程序创建空白任务?

how can i prevent todo app from creating blank task?

我是 React 初学者,我有 3 个问题 1)如何防止创建空白任务(见附图)

2)如何为 UI 选中的任务添加删除线?

3) 为什么我会收到此错误

Warning: Each child in a list should have a unique "key" prop.

我的反应代码:

import React from "react";
import "./styles.css";
let id = 0
const Todo = props => (
  <li>
    <input type="checkbox" checked={props.todo.checked} onChange={props.onToggle} />
    <button onClick={props.onDelete}>delete</button>
    <span>{props.todo.text}</span>
  </li>
)
class App extends React.Component {
  constructor() {
    super()
    this.state = {
      todos: [],
    }
  }
  addTodo() {
    const text = prompt("TODO text please!")
    this.setState({
      todos: [
        ...this.state.todos,
        {id: id++, text: text, checked: false},
      ], 
    })
  }
  removeTodo(id) {
    this.setState({
      todos: this.state.todos.filter(todo => todo.id !== id)
    })
  }
  toggleTodo(id) {
    this.setState({
      todos: this.state.todos.map(todo => {
        
        if (todo.id !== id) return todo
        return {
          id: todo.id,
          text: todo.text,
          checked: !todo.checked,
        }
      })
    })
  }
  render() {
    return (
      <div>
        <div>Todo count: {this.state.todos.length}</div>
        <div>Unchecked todo count: {this.state.todos.filter(todo => !todo.checked).length}</div>
        <button onClick={() => this.addTodo()}>Add TODO</button>
        <ul>
          {this.state.todos.map(todo => (
            <Todo
              onToggle={() => this.toggleTodo(todo.id)}
              onDelete={() => this.removeTodo(todo.id)}
              todo={todo}
             
            />
          ))}
        </ul>
      </div>
    )
  }
}
export default App;

结果: todo-list result image

  1. How can I prevent creating blank tasks(see attached image)

创建任务前必须检查文本是否为空字符串

  addTodo() {
    const text = prompt("TODO text please!")
    if(text !=== ""){ // <- check here
      this.setState({
        todos: [
          ...this.state.todos,
          {id: id++, text: text, checked: false},
        ], 
      })
    }
  }
  1. how to add strikethrough for checked tasks for UI?

这可以通过 css 使用 text-decoration: line-through; 轻松完成,因此,使用 属性 创建一个 class(或者您也可以内联)并且如果任务状态完成,将 class 添加到组件

.text-strike {
  text-decoration: line-through;
}


<Todo className={checked ? 'text-strike' : null}}
  1. why i'm getting this error

每次你循环遍历一个数组来创建视图,React 都需要一些东西来区分所有的组件,所以当需要在 UI 中更新其中一个组件时(重新渲染)它确切地知道应该更新哪一个从而提高性能

  {this.state.todos.map(todo => (
     <Todo
        onToggle={() => this.toggleTodo(todo.id)}
        onDelete={() => this.removeTodo(todo.id)}
        todo={todo}
        key={somethingUnique}  // <- you need to add this key
     />
  ))}
  1. addTodo 函数中添加对空待办事项的验证,如下所示
addTodo() {
    const text = prompt("TODO text please!")
    if(text === undefined || text === "" || text?.trim() === ""){
    alert("You are lazy!!! enter proper value.");
    }else{
    this.setState({
      todos: [
        ...this.state.todos,
        {id: id++, text: text, checked: false},
      ], 
    })
    }

  }
  1. 用于使用 <s> 标签
  2. 醒目的换行文本
  3. 你的反应渲染机制需要区分元素,它使用 key 作为区分器来轻松更新你的 for 循环中对该元素所做的任何更改,因为 dom 不代表 for 循环它是为你做的反应,这是一种让反应理解它必须维护它的界面。 因此,在您的待办事项列表中添加一个键,如下所示
 <Todo
              onToggle={() => this.toggleTodo(todo.id)}
              onDelete={() => this.removeTodo(todo.id)}
              todo={todo}
             key = {todo.id}
            />

查看带有评论的更正:

import React from 'react';

let id = 0;
const Todo = (props) => (
   // style based on props
  <li style={{ textDecoration: props.todo.checked ? 'line-through' : ''}}>
    <input
      type='checkbox'
      checked={props.todo.checked}
      onChange={props.onToggle}
    />
    <button onClick={props.onDelete}>delete</button>
    <span>{props.todo.text}</span>
  </li>
);

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      todos: [],
    };
  }
  addTodo() {
    const text = prompt('TODO text please!');
    // only do this if text has value
    text && this.setState({
        todos: [...this.state.todos, { id: id++, text: text, checked: false }],
      });
  }
  removeTodo(id) {
    this.setState({
      todos: this.state.todos.filter((todo) => todo.id !== id),
    });
  }
  toggleTodo(id) {
    this.setState({
      todos: this.state.todos.map((todo) => {
        if (todo.id !== id) return todo;
        return {
          id: todo.id,
          text: todo.text,
          checked: !todo.checked,
        };
      }),
    });
  }
  render() {
    return (
      <div>
        <div>Todo count: {this.state.todos.length}</div>
        <div>
          Unchecked todo count:{' '}
          {this.state.todos.filter((todo) => !todo.checked).length}
        </div>
        <button onClick={() => this.addTodo()}>Add TODO</button>
        <ul>
          {this.state.todos.map((todo) => (
            <Todo
              key={todo.id} // need a unique key using id
              onToggle={() => this.toggleTodo(todo.id)}
              onDelete={() => this.removeTodo(todo.id)}
              todo={todo}
            />
          ))}
        </ul>
      </div>
    );
  }
}
export default App;