如何基于初始化完成状态实现函数式组件的条件渲染?
解决React组件初始化完成前执行子内容的问题
问题场景
现有一个用于控制内容初始化后显示的组件MyComponent,以及调用它的SomeOtherComponent,代码如下:
MyComponent 代码
export interface MyComponentProps{ children: React.ReactNode } export const MyComponent= (props: MyComponentProps) => { const [isInitialized, setIsInitialized] = useState<boolean>(false); useEffect(() => { // ... 一些初始化操作 console.log("DEBUG APP INITIALIZED"); setIsInitialized(true); }, [setIsInitialized]); return <> {isInitialized && props.children} </> }
SomeOtherComponent 代码
export const SomeOtherComponent = () => { const renderContent = () => { console.log("Render The Content"); return ( <Provider> // .... 加载Provider、div等内容 </Provider> ); } return <div> { isAppEmbeded ? <MyComponent> <h1>Embeded Mode</h1> <div>{renderContent()}</div> </MyComponent> : renderContent() } </div> }
问题现象
控制台输出顺序为:
Render The Content DEBUG APP INITIALIZED
即renderContent在MyComponent初始化完成前就被执行了,不符合预期。
解决方案
核心原因是:JSX在传递子元素时会立即计算所有表达式的值,所以<MyComponent>里的renderContent()会在MyComponent判断isInitialized之前就被调用。我们可以通过将子内容改为回调函数的方式,推迟内容的渲染时机。
步骤1:修改MyComponent的Props与实现
将children类型改为返回ReactNode的函数,仅在初始化完成后调用该函数:
export interface MyComponentProps{ // 改为回调函数类型 children: () => React.ReactNode } export const MyComponent= (props: MyComponentProps) => { const [isInitialized, setIsInitialized] = useState<boolean>(false); useEffect(() => { // ... 初始化操作 console.log("DEBUG APP INITIALIZED"); setIsInitialized(true); }, []); // useState的setter是稳定的,无需加入依赖数组 return <> {/* 初始化完成后才调用回调渲染内容 */} {isInitialized && props.children()} </> }
步骤2:修改调用方的传递方式
直接传递函数(不调用),让MyComponent在合适时机执行它:
export const SomeOtherComponent = () => { const renderContent = () => { console.log("Render The Content"); return ( <Provider> // .... 加载Provider、div等内容 </Provider> ); } return <div> { isAppEmbeded ? <MyComponent> {/* 传递函数本身,而非调用结果 */} {() => ( <> <h1>Embeded Mode</h1> <div>{renderContent()}</div> </> )} </MyComponent> : renderContent() } </div> }
效果验证
修改后控制台输出顺序变为:
DEBUG APP INITIALIZED Render The Content
确保了renderContent仅在初始化完成后执行。
内容的提问来源于stack exchange,提问作者zozonenete
相关产品推荐
相关产品推荐

