【问题标题】:in reactjs, is it possible to create a tab control that does not reset the state of the content?在reactjs中,是否可以创建一个不重置内容状态的选项卡控件?
【发布时间】:2025-11-25 12:05:01
【问题描述】:

这是我的反应钩子代码:

function Panel({children,title}){
    var [count,set_count]=React.useState(0)
    React.useEffect(_=>{
        console.log(title,'mount')
        return _x=>console.log(title,'unmount')
    })
    function onClick(){
        set_count(count+10)
    }
    return <>{count}<button  {...{onClick}}>up</button><div>{children}</div></>
} 
function Tabs({children}){
    var [selected,set_selected]=React.useState(children[0].key)
    var tabs= children.map(x=>{
        function onClick(){
            set_selected(x.key)
        }
        var className=(selected==x.key)?'tab selected':'tab'
        return <div {...{className,onClick,key:x.key}}>{x.props.title||x.key}</div>
    })
    var panel=children.find(x=>x.key==selected)
    return <><div>{tabs}</div>{panel}</>
}
function TabsPage(){
    return <Tabs>
        <Panel key='the_tab1' title='The tab1 title'> tab1<b>rrr</b></Panel>
        <Panel key='the_tab2' title='The tab2 title'> tab2</Panel>
        </Tabs>
}

目标是使用反应钩子创建一个简单的带有任意内容的选项卡控件(称为面板)。该代码有效,除了每次用户更改活动选项卡时面板组件都会安装/卸载。结果面板状态重置。

我的问题:如何在更改选项卡时不重置状态?不使用 redux 等全局状态存储是否有可能?

【问题讨论】:

    标签: reactjs react-redux


    【解决方案1】:

    状态会在选项卡更改时重置,因为每次更改所选选项卡时都会在选项卡组件中重新渲染面板变量。要保持状态,您有 2 个选项:

    • 将状态保留在 TabsPage 组件中,而不是 redux,这样在卸载面板时不会丢失。
    • 始终呈现所有选项卡,但仅显示选定的选项卡(使用 CSS 属性,如显示或可见性)。这样,组件就不会被卸载,因此您可以保持状态。

    另外,即使它与您的问题无关,我想指出,使用您在 Panel 组件中使用的 useEffect 代码,您不会跟踪安装/卸载状态。相反,它在每次渲染时触发。如果你希望你的效果在挂载和卸载时被调用一次,你需要为你的效果添加一个依赖数组。检查React documentation

    【讨论】:

    • 是的,这是有道理的,并且与我在其他地方读到的内容一致。我希望 react 能够以某种方式配置组件,而不是在挂载/卸载时重置状态
    【解决方案2】:

    这是相当的误解,认为 react hook 中的useEffect 有挂载效果,而useEffect 中的 clean up 有卸载效果(即使我在学习 hooks 时也有这种想法)。

    简而言之,每个渲染都有自己的状态、道具和效果。并且在效果再次发生之前调用了清理内部的清理函数。那就是当每个效果的依赖关系出现时,它决定了useEffect 的发生时间。目前,useEffect 在每个渲染上都会执行,因为它没有依赖关系。

    我强烈建议阅读此博客 post 以了解 useEffect 的行为方式。

    解决这个问题的方法是实现活动面板TabsPage 并将 selectedKey 发送到Panel。如果键相同,您可以切换显示内容。

    所以组件看起来和这个类似

    function TabsPage() {
      const [selectedKey, setSelectedKey] = React.useState(the_tab1);
      const handlePanelClick = useCallback((id) => {
        setSelectedKey(id);
      }, []);
      return (
        <Tabs>
          <Panel
            key="the_tab1"
            title="The tab1 title"
            selectedKey={selectedKey}
            onClick={handlePanelClick}
          >
            tab1<b>rrr</b>
          </Panel>
          <Panel
            key="the_tab2"
            title="The tab2 title"
            selectedKey={selectedKey}
            onClick={handlePanelClick}
          >
            tab2
          </Panel>
        </Tabs>
      );
    }
    
    function Panel({ key, children, handlePanelClick, selectedKey }) {
      return (
        <>
          {/** to show hide the panel */}
          <button onClick={() => handlePanelClick(key)}>+</button>
          {key === selectedKey && <div>{children}</div>}
        </>
      );
    }
    

    【讨论】:

      最近更新 更多