简体   繁体   English

显示/隐藏 React 组件不维护内部 state

[英]Showing/hiding React components does not maintain internal state

I am trying to hide/show components in React based on some state.我试图根据一些 state 在 React 中隐藏/显示组件。 The main issue I am facing is to maintain the internal state of the components during hiding and showing.我面临的主要问题是在隐藏和显示期间维护组件的内部 state。 The below is the code that does what I expect and maintains the state of each of the components (Africa, Europe, America, Asia):下面是执行我期望并维护每个组件(非洲、欧洲、美洲、亚洲)的 state 的代码:

render() {
    const {selectedTab} = this.state;
    return (
        <div>
            <div className={selectedTab === 'africa' ? '' : 'hidden-tab'}><Africa /></div>
            <div className={selectedTab === 'europe' ? '' : 'hidden-tab'}><Europe /></div>
            <div className={selectedTab === 'america' ? '' : 'hidden-tab'}><America /></div>
            <div className={selectedTab === 'asia' ? '' : 'hidden-tab'}><Asia /></div>
        </div>
    )
}


//regions.scss
.hidden-tab {
   display: none
}

However, I am not satisfied with the cleanliness of the above code and would like to refactor, which is where I am facing issues.但是,我对上述代码的简洁性不满意,并想重构,这是我面临的问题。 This is what I have done:这就是我所做的:

render() {
    const {selectedTab} = this.state;
    const tabToRegionMap = {
        'africa': <Africa />,
        'eruope': <Europe />,
        'america': <America />,
        'asia': <Asia />
    };
    const {[selectedTab]: selectedRegion, ...regionsToHide} = tabToRegionMap;

    return (
        <div>
            <div className={'hidden-tab'}>
                {Object.values(regionsToHide)}
            </div>
            {selectedRegion}
        </div>
    );

The above try does show/hide the copmonents but does not maintain the internal state of the components during hiding/showing - it seems like they are being unmounted and remounted every time.上述尝试确实显示/隐藏了组件,但在隐藏/显示期间不维护组件的内部 state - 似乎每次都在卸载和重新安装它们。

Could anyone please help me solve the problem or suggest a better way of doing it?任何人都可以帮我解决问题或提出更好的方法吗? That would be much appreciated.那将不胜感激。

PS I would prefer not to move the state to the parent or Redux as there is a lot of boilerplate involved and the states of the individual components are very complex. PS 我不希望将 state 移动到父级或 Redux 因为涉及很多样板,并且各个组件的状态非常复杂。

That happens because of Reacts reconciliation algorithm.发生这种情况是因为 Reacts协调算法。 When <ComponentA> is rendered on some place and on next render you render <ComponentB> on that place, the previous component is unmounted - and state is gone;<ComponentA>在某个地方渲染并且在下一次渲染时您在那个地方渲染<ComponentB>时,前一个组件被卸载 - 并且 state 消失了; you do this I suppose in {selectedRegion} it gets different component when user switches tab.你这样做我想在{selectedRegion}中当用户切换选项卡时它会得到不同的组件。

Usually you have to ways to implement tab like functionality:通常你必须有办法实现类似标签的功能:

  • use display:none property on hidden tabs (state is not lost in that case because you just changed CSS prop)在隐藏选项卡上使用display:none属性(在这种情况下状态不会丢失,因为您刚刚更改了 CSS 属性)
  • Render tab content as react component - and keep mounted only the active tab component (what you have basically, but state gets lost that way, so you need to lift state up )将选项卡内容呈现为反应组件 - 并仅安装活动选项卡组件(您基本上拥有,但 state 会这样丢失,因此您需要提升 state

But I think you can also try following approach:但我认为您也可以尝试以下方法:

let Tab = (props) => {
  let [state, setState] = React.useState(0);
  if (props.hide) return null;
  return <div onClick={() => setState(state + 1)}>{state}</div>;
};
export default function App() {
  let [hide, setHide] = React.useState(false);

  return (
    <div>
      <Tab hide={hide} />
      <div
        onClick={() => {
          setHide(!hide);
        }}
      >
        Hide/Show Tab
      </div>
    </div>
  );
}

Change tab state, then hide/show it, and see state is not lost.更改选项卡 state,然后隐藏/显示它,并查看 state 没有丢失。 Although I haven't used this pattern much.虽然我没有太多使用这种模式。

If I understand your question you are essentially looking for a way to clean up the code and keep the children components mounted.如果我理解您的问题,您实际上是在寻找一种清理代码保持子组件安装的方法。

The issue with the proposed solution is that each time it is rendered and supposed to hide tabs is it recreating the elements.提议的解决方案的问题在于,每次渲染并隐藏选项卡时,它都会重新创建元素。 They are swapping between being rendered into the <div className={'hidden-tab'}> and not, remounting each time when selected tab updates.它们在渲染到<div className={'hidden-tab'}>和不渲染之间进行交换,每次选定选项卡更新时都会重新安装。

I suggest just abstracting the div elements into a new component that conditionally applies the 'hidden-tab' classname.我建议将div元素抽象为一个有条件地应用'hidden-tab'类名的新组件。

const Tab = ({ children, selectedTab, tab }) => (
  <div className={selectedTab === tab ? '' : 'hidden-tab'}>
    {children}
  </div>
);

... ...

render() {
  const {selectedTab} = this.state;
  return (
    <div>
      <Tab selectedTab={selectedTab} tab='africa'><Africa /></Tab>
      <Tab selectedTab={selectedTab} tab='europe'><Europe /></Tab>
      <Tab selectedTab={selectedTab} tab='america'><America /></Tab>
      <Tab selectedTab={selectedTab} tab='asia'><Asia /></Tab>
    </div>
  )
}

If you wanted to take it a step further, you could also abstract the wrapping div of these tabs into a container component that stored the selected tab and provided the value to children tabs via the Context API so a selectedTab wouldn't need to be explicitly passed to each.如果您想更进一步,您还可以将这些选项卡的包装div抽象到一个容器组件中,该组件存储所选选项卡并通过上下文 API 将值提供给子选项卡,因此不需要明确selectedTab传递给每个人。

Example:例子:

import { createContext, useContext } from "react";

const TabContext = createContext({
  selectedTab: null
});

const useSelectedTab = () => useContext(TabContext);

const Tabs = ({ children, selectedTab }) => (
  <TabContext.Provider value={{ selectedTab }}>{children}</TabContext.Provider>
);

const Tab = ({ children, tab }) => {
  const { selectedTab } = useSelectedTab();
  return (
    <div className={selectedTab === tab ? "" : "hidden-tab"}>{children}</div>
  );
};

Usage:用法:

render() {
  const {selectedTab} = this.state;
  return (
    <Tabs selectedTab={selectedTab}>
      <Tab tab='africa'><Africa /></Tab>
      <Tab tab='europe'><Europe /></Tab>
      <Tab tab='america'><America /></Tab>
      <Tab tab='asia'><Asia /></Tab>
    </div>
  )
}

编辑显示隐藏反应组件不维护内部状态

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM