menu
首页文章相册工具关于
search
...

使用 React 创建待办事项列表

2025/02/25
eye-

当我第二次换工作时,面试官要求我使用 React 创建一个待办事项列表。我认为这是一个很好的问题来测试候选人的思考和编码能力。不像刻板的写作,它更像是一个真实的面试问题。

让我们从待办事项列表的基本结构开始。

首先,我们需要一个输入字段来添加新的待办事项。

<input type="text" placeholder="new thing to be done" />

其次,我们需要一个列表来显示所有的待办事项。

const [todos, setTodos] = useState([])

然后我们需要渲染列表:

{
  todos.map((todo) => <li key={todo.id}>{todo.text}</li>)
}

现在,让我们把这些组件组合在一起。

const [todos, setTodos] = useState([])

return (
  <div>
    <input type="text" placeholder="new thing to be done" />
    <ul>
      {todos.map((todo) => (
        <li key={todo.id}>{todo.text}</li>
      ))}
    </ul>
  </div>
)

现在,我们需要处理输入字段。我们可以使用表单来包装输入字段。

const inputRef = useRef(null)

<form onSubmit={handleSubmit}>
  <input type="text" placeholder="new thing to be done" ref={inputRef} />
</form

为什么我们需要使用表单?因为我们想要在输入新的待办事项时防止页面刷新。当然,你也可以选择其他方式来处理这个问题。

const handleSubmit = (e) => {
  e.preventDefault()
  setTodos([...todos, { id: Date.now(), label: inputRef.current.value }])
  inputRef.current.value = ""
}

让我们把这些组件组合在一起。

function TodoList() {
  const inputRef = useRef(null)
  const [todos, setTodos] = useState([])

  const handleSubmit = (e) => {
    e.preventDefault()
    setTodos([...todos, { id: Date.now(), label: inputRef.current.value }])
    inputRef.current.value = ""
  }

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input type="text" placeholder="new thing to be done" ref={inputRef} />
      </form>
      <ul>
        {todos.map((todo) => (
          <li key={todo.id}>{todo.label}</li>
        ))}
      </ul>
    </div>
  )
}

现在我们可以添加新的待办事项。但我们需要在待办事项完成或未完成时切换它。我们应该为待办事项添加一个复选框。如果选中,则添加删除线样式。

const handleToggle = (id) => {
  setTodos(
    todos.map((todo) => (todo.id === id ? { ...todo, done: !todo.done } : todo))
  )
}

<li key={todo.id}>
    <input
        type="checkbox"
        checked={todo.done}
        onChange={() => handleToggle(todo.id)}
    />
    <label className={item.done ? "done" : "undo"}>{todo.label}</label>
</li>

之后我们还需要添加一个按钮来删除待办事项。

<li key={todo.id}>
  <input
    type="checkbox"
    checked={todo.done}
    onChange={() => handleToggle(todo.id)}
  />
  {todo.label}
  <button onClick={() => handleDelete(todo.id)}>x</button>
</li>
const handleDelete = (id) => {
  setTodos(todos.filter((todo) => todo.id !== id))
}

就是这样。我们有了一个待办事项列表。

function TodoList() {
  const inputRef = useRef(null)
  const [todos, setTodos] = useState([])

  const handleSubmit = (e) => {
    e.preventDefault()
    setTodos([
      ...todos,
      { id: Date.now(), label: inputRef.current.value, done: false },
    ])
    inputRef.current.value = ""
  }

  const handleDelete = (id) => {
    setTodos(todos.filter((todo) => todo.id !== id))
  }

  const handleToggle = (id) => {
    setTodos(
      todos.map((todo) =>
        todo.id === id ? { ...todo, done: !todo.done } : todo
      )
    )
  }

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input type="text" placeholder="new thing to be done" ref={inputRef} />
      </form>
      <ul>
        {todos.map((todo) => (
          <li key={todo.id}>
            <input
              type="checkbox"
              checked={todo.done}
              onChange={() => handleToggle(todo.id)}
            />
            <label className={item.done ? "done" : "undo"}>{todo.label}</label>
            <button onClick={() => handleDelete(todo.id)}>x</button>
          </li>
        ))}
      </ul>
    </div>
  )
}

如果你能完成上述内容,我认为你的答案基本符合要求。

但我们可以做得更好,比如:

  • 我们可以将待办事项列表组件提取到一个单独的组件中。
  • 我们可以通过使用 CSS 让待办事项列表组件更美观。
  • 我们可以在待办事项为空时添加过滤器。
  • 我们可以使用 memo 和 useCallback 来优化待办事项列表组件。
  • 我们可以使用本地存储来存储待办事项列表。
  • ...

如果你能完成上述内容,我认为你的答案是优秀的。试试看,祝你好运!

深入理解 React startTransition