React中父组件状态变更时如何避免子组件重渲染?
问题:父组件控制子组件显隐时保留子组件状态(不使用状态管理)
你当前遇到的核心问题不是重渲染,而是当父组件中{open && <MyComponentMemoized />}为false时,子组件会被完全卸载——再次显示时会创建全新的组件实例,内部状态自然会重置。React.memo只能阻止组件在props不变时的重渲染,无法解决卸载/重新挂载导致的状态丢失问题。
下面是两种无需状态管理的解决方案:
方案1:用CSS控制显示隐藏(不卸载组件)
通过CSS的display属性控制子组件的显示与隐藏,让组件始终存在于DOM中,避免卸载导致的状态丢失。
修改App.js
import "./styles.css"; import React, { useState, useCallback } from "react"; import MyComponent from "./components/MyComponent"; export default function App() { const [open, setOpen] = useState(false); const handleClick = useCallback(() => { setOpen((prevOpen) => !prevOpen); }, []); return ( <div className="App"> <button onClick={handleClick}>{open ? "Close div" : "Open div"}</button> {/* 用style控制显示,不卸载组件 */} <MyComponent style={{ display: open ? "block" : "none" }} /> </div> ); }
可选:调整MyComponent接收样式
// MyComponent.js import React, { memo } from "react"; const MyComponent = ({ style }) => { const [showText1, setShowText1] = useState(false); const [showText2, setShowText2] = useState(false); const [showText3, setShowText3] = useState(false); const handleShowText1 = () => setShowText1(!showText1); const handleShowText2 = () => setShowText2(!showText2); const handleShowText3 = () => setShowText3(!showText3); return ( <div style={style}> Hello there <button onClick={handleShowText1}>Show text 1</button> {showText1 && <div>Text 1!</div>} <button onClick={handleShowText2}>Show text 2</button> {showText2 && <div>Text 2!</div>} <button onClick={handleShowText3}>Show text 3</button> {showText3 && <div>Text 3!</div>} </div> ); }; export default memo(MyComponent);
方案2:将子组件状态提升到父组件
如果不想让子组件始终存在于DOM,可以把它的内部状态移到父组件中保存,通过props传递给子组件,这样即使子组件卸载,状态也会保留在父组件中,再次挂载时可以恢复。
修改App.js
import "./styles.css"; import React, { useState, useCallback } from "react"; import MyComponent from "./components/MyComponent"; export default function App() { const [open, setOpen] = useState(false); // 保存子组件的状态 const [textStates, setTextStates] = useState({ showText1: false, showText2: false, showText3: false }); const handleClick = useCallback(() => { setOpen((prevOpen) => !prevOpen); }, []); // 统一处理子组件的状态切换 const handleTextToggle = (key) => { setTextStates(prev => ({ ...prev, [key]: !prev[key] })); }; return ( <div className="App"> <button onClick={handleClick}>{open ? "Close div" : "Open div"}</button> {open && ( <MyComponent textStates={textStates} onTextToggle={handleTextToggle} /> )} </div> ); }
修改MyComponent.js
import React, { memo } from "react"; const MyComponent = ({ textStates, onTextToggle }) => { return ( <div> Hello there <button onClick={() => onTextToggle("showText1")}>Show text 1</button> {textStates.showText1 && <div>Text 1!</div>} <button onClick={() => onTextToggle("showText2")}>Show text 2</button> {textStates.showText2 && <div>Text 2!</div>} <button onClick={() => onTextToggle("showText3")}>Show text 3</button> {textStates.showText3 && <div>Text 3!</div>} </div> ); }; export default memo(MyComponent);
内容的提问来源于stack exchange,提问作者devD
相关产品推荐
相关产品推荐

