【问题标题】:Showing/hiding React components does not maintain internal state显示/隐藏 React 组件不会保持内部状态
【发布时间】:2021-12-31 13:50:27
【问题描述】:

我正在尝试根据某些状态在 React 中隐藏/显示组件。我面临的主要问题是在隐藏和显示期间保持组件的内部状态。下面是执行我期望的代码并维护每个组件(非洲、欧洲、美洲、亚洲)的状态:

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
}

但是,我对上述代码的简洁性不满意,并想重构,这是我面临的问题。这就是我所做的:

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>
    );

上述尝试确实显示/隐藏了组件,但在隐藏/显示期间不保持组件的内部状态 - 似乎每次都在卸载和重新安装它们。

谁能帮我解决问题或提出更好的解决方法?那将不胜感激。

PS 我不希望将状态移动到父级或 Redux,因为这涉及到很多样板,并且各个组件的状态非常复杂。

【问题讨论】:

    标签: javascript reactjs ecmascript-6 react-state-management


    【解决方案1】:

    如果我理解您的问题,您实际上是在寻找一种清理代码的方法保持子组件的安装。

    建议的解决方案的问题是,每次渲染并隐藏选项卡时,它都会重新创建元素。它们在渲染到&lt;div className={'hidden-tab'}&gt; 和不渲染之间切换,每次选择的选项卡更新时都重新安装。

    我建议将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>
      )
    }
    

    如果您想更进一步,您还可以将这些选项卡的包装 div 抽象为一个容器组件,该容器组件存储所选选项卡并通过上下文 API 为子选项卡提供值,因此 selectedTab不需要显式传递给每个。

    例子:

    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>
      );
    };
    

    用法:

    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>
      )
    }
    

    【讨论】:

    • 感谢您的建议@DrewReese!我尝试使用第一个按预期显示/隐藏的解决方案。但是,内部状态仍未维持。知道为什么会这样吗?
    • @John 您有这些国家/地区组成部分之一的示例以及您希望它们维持的那种状态吗?如果它们保持安装状态,那么我不明白为什么即使隐藏状态也不会保持状态。我将在我链接的 CSB 中进行测试。
    • 这里很难粘贴,因为它们是非常复杂的组件,使用我们内部 React 框架中的组件作为主要组件。也许这与我从框架中提取的那些组件有关。
    • 我尝试将新组件放在类方法和 render() 中。这是我要去错的地方吗?像这样:``` buildTabContent() { const Tab = ({ children, selectedTab, tab }) => (
      {children}
      ); } render() { return this.buildTabContent(); } ```
    • @John 这是我的 CSB 的 fork,我在其中为每个 Country 组件添加了一些基本状态,由每个渲染的组件独立更新,甚至将 display: none; 应用于隐藏的组件和它们保持其内部状态。当然,CSB 是我建议的第二个实现,但它实际上只是为您抽象出活动选项卡值。如果没有看到您的更新版本,很难说为什么您的组件没有保持安装状态。
    猜你喜欢
    • 2022-10-25
    • 2015-02-27
    • 1970-01-01
    • 2020-10-10
    • 1970-01-01
    • 2012-11-12
    • 2013-07-23
    • 1970-01-01
    • 2022-01-26
    相关资源
    最近更新 更多