React组件非预期重渲染问题:点击Price区域输入控件后filtersection状态被重置为categories
问题根源与修复方案
我一眼就看出问题出在哪了——你把leftSideBar和rightSideBar这两个组件定义在了父组件的内部!
为什么会出现状态重置的情况?
每次父组件发生重渲染(比如你点击Price区域的输入控件触发handlePrice,进而导致父组件状态更新),这两个内部定义的组件都会被重新创建成全新的函数。React会把旧的组件实例卸载,再挂载新的组件实例——这就相当于整个侧边栏被“重启”了一遍,关联的filtersection状态自然就回到初始值"categories"了。
修复方案(推荐第一种)
方案1:将子组件移到父组件外部
把leftSideBar和rightSideBar提取成独立的组件,通过props传递需要的状态和回调函数。这样组件不会随着父组件重渲染而被重新创建,状态关联会保持稳定:
// 独立定义子组件,放在父组件外部 const LeftSideBar = ({ setFilterSection }) => { return ( <div className="leftsidebarbody"> <div onClick={() => setFilterSection("categories")}>Categories</div> <div onClick={() => setFilterSection("prices")}>Price</div> </div> ); }; const RightSideBar = ({ filtersection, categories, selectedCategories, handleCheck, prices, selectedPrice, handlePrice }) => { return ( <div className="rightsidebarbody"> {filtersection === "categories" && ( <div className="block"> {categories.map((category, index) => { return ( <div className="categories" key={index}> <input type="checkbox" id={category._id} onChange={handleCheck} checked={selectedCategories.includes(category._id)} /> <div>{category.name}</div> </div> ); })} </div> )} {filtersection === "prices" && ( <div className="block"> {prices.map((price, index) => { return ( <div className="categories" key={index}> <input name={price} value={`${price._id}`} type="radio" onChange={handlePrice} checked={selectedPrice.includes(price._id)} /> {price.name} </div> ); })} </div> )} </div> ); }; // 父组件中使用子组件 const ParentComponent = () => { const [filtersection, setFilterSection] = React.useState("categories"); // 假设你已经定义了以下状态和回调: // const [categories, setCategories] = React.useState([]); // const [selectedCategories, setSelectedCategories] = React.useState([]); // const handleCheck = () => { /* ... */ }; // const [prices, setPrices] = React.useState([]); // const [selectedPrice, setSelectedPrice] = React.useState([]); // const handlePrice = () => { /* ... */ }; return ( <div className="parent-container"> <LeftSideBar setFilterSection={setFilterSection} /> <RightSideBar filtersection={filtersection} categories={categories} selectedCategories={selectedCategories} handleCheck={handleCheck} prices={prices} selectedPrice={selectedPrice} handlePrice={handlePrice} /> </div> ); };
方案2:若必须留在父组件内部,用useMemo缓存组件
如果因为某些原因(比如需要访问父组件的私有变量)必须把组件定义在父组件内部,那么可以用useMemo来缓存组件实例,避免每次重渲染都重新创建:
const ParentComponent = () => { const [filtersection, setFilterSection] = React.useState("categories"); // 其他状态和回调... // 用useMemo缓存LeftSideBar组件 const LeftSideBar = React.useMemo(() => { return () => ( <div className="leftsidebarbody"> <div onClick={() => setFilterSection("categories")}>Categories</div> <div onClick={() => setFilterSection("prices")}>Price</div> </div> ); }, [setFilterSection]); // 用useMemo缓存RightSideBar组件 const RightSideBar = React.useMemo(() => { return () => ( <div className="rightsidebarbody"> {/* 原有内容不变 */} </div> ); }, [filtersection, categories, selectedCategories, handleCheck, prices, selectedPrice, handlePrice]); return ( <div> <LeftSideBar /> <RightSideBar /> </div> ); };
额外优化建议
为了避免不必要的重渲染,你还可以用React.useCallback包裹handleCheck和handlePrice这两个回调函数,确保它们不会在父组件重渲染时被频繁重新创建:
const handleCheck = React.useCallback((e) => { // 你的原有逻辑 }, [selectedCategories]); const handlePrice = React.useCallback((e) => { // 你的原有逻辑 }, [selectedPrice]);
内容的提问来源于stack exchange,提问作者Nilesh102001
相关产品推荐
相关产品推荐

