You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Hooks中如何将单状态管理组件改写为多独立useState实现?

将单状态React电影组件改写为多useState实现的修正方案

当然可以把单状态管理的组件拆分成多个独立的useState,你的拆分思路完全没问题,但代码里存在几处语法和逻辑错误,我来帮你修正并解释关键点:

存在的问题梳理

  • handleWatchedBtn函数错误:
    • setMovies接收的应该是更新后的数组,而不是包含movies属性的对象;
    • 修改电影的watched状态时,需要展开原电影对象再修改属性,否则会丢失原对象的其他字段。
  • handleWatchedChange函数错误:
    • setfilterByWatch直接传入筛选值即可,不需要包装成对象,因为这个状态本身就是字符串类型。
  • 状态命名规范建议:
    • React社区通常使用小驼峰命名状态(比如keyword而非Keyword),这样代码风格更统一。

修正后的完整代码

import React, { useEffect, useState } from "react";
import { getAllMovies } from "./components/Transportlayer";

const App = () => {
  const [movies, setMovies] = useState([]);
  const [keyword, setKeyword] = useState("");
  const [overSeven, setOverSeven] = useState(false);
  const [loading, setLoading] = useState(true);
  const [filterByWatch, setFilterByWatch] = useState("ALL"); // 修正命名为小驼峰

  useEffect(() => {
    getAllMovies().then((response) => {
      setMovies(
        response.map((item) => ({
          id: item.id,
          name: item.name,
          rate: item.rate,
          watched: false,
        }))
      );
      setLoading(false);
    });
  }, []);

  function handleWatchedBtn(id) {
    // 正确更新movies数组:遍历并修改指定id的电影的watched状态
    setMovies(prevMovies => prevMovies.map((movie) => {
      if (movie.id === id) {
        return { ...movie, watched: !movie.watched }; // 展开原对象,只修改watched
      }
      return movie;
    }));
  }

  function handleKeywordChange(e) {
    setKeyword(e.target.value);
  }

  function handleOverSevenChange(e) {
    setOverSeven(e.target.checked);
  }

  function handleWatchedChange(filter) {
    // 直接传入筛选值,不需要包装成对象
    setFilterByWatch(filter);
  }

  function filterItems() {
    return movies
      .filter((item) => item.name.toLowerCase().includes(keyword.toLowerCase()))
      .filter((item) => (overSeven ? item.rate > 7 : true))
      .filter((item) => 
        filterByWatch === "ALL" 
          ? true 
          : item.watched === (filterByWatch === "WATCHED")
      );
  }

  if (loading) {
    return "Please wait...";
  }

  return (
    <div>
      <div>
        <div>
          Keyword
          <input type="text" value={keyword} onChange={handleKeywordChange} />
        </div>
        <div>
          <button onClick={() => handleWatchedChange("ALL")}>all</button>
          <button onClick={() => handleWatchedChange("WATCHED")}>done</button>
          <button onClick={() => handleWatchedChange("NOT_WATCHED")}>
            undone
          </button>
        </div>
        <div>
          Only over 7.0
          <input
            type="checkbox"
            checked={overSeven}
            onChange={handleOverSevenChange}
          />
        </div>
        <div>
          <ul>
            {filterItems().map((movie) => (
              <li key={movie.id} data-id={movie.id}> {/* 添加key属性,符合React列表渲染规范 */}
                {`${movie.name} ${movie.rate}`}
                <button onClick={() => handleWatchedBtn(movie.id)}>
                  {movie.watched ? "done" : " undone"}
                </button>
              </li>
            ))}
          </ul>
        </div>
      </div>
    </div>
  );
};

export default App;

额外优化点说明

  • 在列表渲染时添加了key属性,这是React列表渲染的必要规范,能提升渲染性能并避免警告;
  • 把setfilterByWatch重命名为setFilterByWatch,符合小驼峰的命名规范;
  • 更新movies时使用了函数式更新(prevMovies => ...),这是更安全的方式,确保我们基于最新的状态进行修改,避免闭包导致的状态不一致问题。

拆分状态的优势在于每个状态职责单一,更新逻辑更清晰,不需要每次更新都展开整个状态对象,同时也让组件的可读性和可维护性更强。

内容的提问来源于stack exchange,提问作者Negin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 10:14:06