ReactJS中设置状态后Checkbox值未更新问题求助
问题描述
我开发的应用包含两个区域:左侧为分类栏,右侧展示对应分类下的项目。每个分类下设有全选和取消全选按钮,能看到代码中的状态已发生变更(已在HTML中格式化输出),但Checkbox的状态值并未更新,求解决。
相关代码
App.js
import { useEffect, useState, useMemo } from "react"; import { SidebarItem } from "./SideBarItem"; import { RightSection } from "./RightSection"; import "./styles.css"; export default function App() { const dummyJson = useMemo(() => { return { cat1: { id: "cat1", name: "Category 1", tiles: [ { tileName: "abc", searchable: true, checked: false }, { tileName: "def", searchable: true, checked: true } ] }, cat2: { id: "cat2", name: "Category 2", tiles: [ { tileName: "ab", searchable: true, checked: true }, { tileName: "xyz", searchable: true, checked: false } ] }, cat3: { id: "cat3", name: "Category 3", tiles: [ { tileName: "lmn", searchable: true, checked: true }, { tileName: "", searchable: false, checked: false } ] } }; }, []); const [json, setJson] = useState(dummyJson); const [active, setActive] = useState(dummyJson["cat1"]); return ( <> <div className="container"> <div> <ul> {Object.values(json).map((details) => { const { id, name } = details; return ( <SidebarItem key={name} name={name} {...{ isActive: id === active.id, setActive: () => setActive(details) }} /> ); })} </ul> </div> <RightSection name={active.name} apps={active.tiles} {...{ json, setJson }} /> </div> <p>{JSON.stringify(json, null, 2)}</p> </> ); }
RightSection.js
export const RightSection = ({ name, apps, json, setJson }) => { function handleSelectAll(categoryName, type) { const checked = type === "Select All" ? true : false; const updated = Object.fromEntries( Object.entries(json).map(([key, category]) => { if (category.name !== categoryName) { return [key, category]; } const { name, tiles, ...rest } = category; return [ key, { name, ...rest, tiles: tiles.map((item) => ({ ...item, checked })) } ]; }) ); setJson(updated); } return ( <> <div> <input type="button" value={`select all under ${name}`} onClick={() => handleSelectAll(name, "Select All")} /> <input type="button" value={`unselect all under ${name}`} onClick={() => handleSelectAll(name, "Unselect All")} /> <h4 style={{ color: "blue" }}>{name} Items</h4> {apps.map((app) => { return ( <section key={app.tileName}> <input checked={app.checked} type="checkbox" /> <span key={app.tileName}>{app.tileName}</span> <br /> </section> ); })} </div> </> ); };
问题原因与解决方案
问题原因
点击全选/取消全选按钮后,json状态确实更新了,但右侧展示的apps来自active状态,而active还是初始时的对象引用,没有同步更新为json中最新的分类数据,导致Checkbox渲染的还是旧的checked值。
解决方案
推荐以下两种简洁的修复方式:
方式1:通过ID跟踪激活分类,实时从json取最新数据
修改App.js,将active状态替换为activeId,每次直接从json中读取对应ID的分类数据,避免状态不同步:
import { useEffect, useState, useMemo } from "react"; import { SidebarItem } from "./SideBarItem"; import { RightSection } from "./RightSection"; import "./styles.css"; export default function App() { const dummyJson = useMemo(() => { return { cat1: { id: "cat1", name: "Category 1", tiles: [ { tileName: "abc", searchable: true, checked: false }, { tileName: "def", searchable: true, checked: true } ] }, cat2: { id: "cat2", name: "Category 2", tiles: [ { tileName: "ab", searchable: true, checked: true }, { tileName: "xyz", searchable: true, checked: false } ] }, cat3: { id: "cat3", name: "Category 3", tiles: [ { tileName: "lmn", searchable: true, checked: true }, { tileName: "", searchable: false, checked: false } ] } }; }, []); const [json, setJson] = useState(dummyJson); // 用ID跟踪激活分类,而非直接存储对象 const [activeId, setActiveId] = useState("cat1"); // 实时从json中获取最新的激活分类数据 const active = json[activeId]; return ( <> <div className="container"> <div> <ul> {Object.values(json).map((details) => { const { id, name } = details; return ( <SidebarItem key={name} name={name} {...{ isActive: id === activeId, setActive: () => setActiveId(id) }} /> ); })} </ul> </div> <RightSection name={active.name} apps={active.tiles} {...{ json, setJson }} /> </div> <p>{JSON.stringify(json, null, 2)}</p> </> ); }
方式2:监听json变化,同步更新active状态
如果想保留原有active状态结构,可添加useEffect监听json变化,当json更新时同步刷新active:
import { useEffect, useState, useMemo } from "react"; import { SidebarItem } from "./SideBarItem"; import { RightSection } from "./RightSection"; import "./styles.css"; export default function App() { const dummyJson = useMemo(() => { return { cat1: { id: "cat1", name: "Category 1", tiles: [ { tileName: "abc", searchable: true, checked: false }, { tileName: "def", searchable: true, checked: true } ] }, cat2: { id: "cat2", name: "Category 2", tiles: [ { tileName: "ab", searchable: true, checked: true }, { tileName: "xyz", searchable: true, checked: false } ] }, cat3: { id: "cat3", name: "Category 3", tiles: [ { tileName: "lmn", searchable: true, checked: true }, { tileName: "", searchable: false, checked: false } ] } }; }, []); const [json, setJson] = useState(dummyJson); const [active, setActive] = useState(dummyJson["cat1"]); // 监听json变化,同步更新active为最新分类数据 useEffect(() => { setActive(json[active.id]); }, [json]); return ( <> <div className="container"> <div> <ul> {Object.values(json).map((details) => { const { id, name } = details; return ( <SidebarItem key={name} name={name} {...{ isActive: id === active.id, setActive: () => setActive(details) }} /> ); })} </ul> </div> <RightSection name={active.name} apps={active.tiles} {...{ json, setJson }} /> </div> <p>{JSON.stringify(json, null, 2)}</p> </> ); }
两种方式都能让右侧Checkbox实时同步json中的checked状态,推荐方式1,它更简洁且避免了额外的状态同步逻辑。
内容的提问来源于stack exchange,提问作者user16860065
相关产品推荐
相关产品推荐

