按指定顺序渲染 React 组件

IT技术 javascript reactjs
2021-05-26 17:12:43

很难找到有关此特定模式的任何信息,而且我什至不确定如何用搜索词来描述它,因此如果这是一个重复的问题,我深表歉意(尽管我认为不是)。

我想根据传递给应用程序的顺序输出 React 布局,用户可以通过设置面板设置该顺序。这个想法是在我希望用户能够重新排列的页面上输出几个不同的容器。需要注意的是,此顺序在应用程序呈现后不可更改。(我希望用户能够说“按顺序显示 PanelA、PanelC 和 PanelB”)

现在,我已经想出了如何使用以下模式完成此操作:

// user-ordered array is passed to the app:
    const settings = {
        layout: [
            "panela",
            "panelb",
            "panelc"
        ]
    }

    class MyComponent extends React.Component {
        constructor(props) {
            super(props)
            this.state = {
                // some state
            }
        }
        renderComponentsInOrder() {
            return settings.layout.map(component => {
                switch(component) {
                    case "panela":
                        return 
                            <PanelA {.../* some state */} />
                    case "panelb":
                        return 
                            <PanelB {.../* some state */} />
                    case "panelc":
                        return 
                            <PanelC {.../* some state */} />
                    default: return null
                }
            })
        }

        render() {
            return this.renderComponentsInOrder()
        }
    }

但这让我觉得效率很低。每次渲染运行时不需要重新计算组件的顺序,因为在应用程序运行时顺序不会改变。我试过做一些事情,比如记住 renderComponentsInOrder 方法来缓存计算的布局或重命名 settings.layout 数组中的值并直接调用它们,但一直无法得到任何工作,因为组件需要更新基于状态。

任何帮助或建议将不胜感激。谢谢!

编辑:理想情况下,我正在寻找基于 JS 的解决方案,因为兼容性有点问题,我不想仅仅依赖浏览器的 CSS 实现。

2个回答

布兰登给出的答案略有不同。您可以使用一个函数来根据状态/props生成组件:

const settings = {
    layout: [
        "panela",
        "panelb",
        "panelc"
    ]
};

const panels = settings.layout.map(c => {
  switch (c) {
    case "panela": return (props, state) => <PanelA key="a" foo={state.foo} />
    case "panelb": return (props, state) => <PanelB key="b" bar={state.bar} />
  }
});

// Now use panels array to render:

class MyComponent extends React.Component {
  render() {
    const props = this.props;
    const state = this.state;
    const ordered = panels.map(p => p(props, state));

    return <div>{ordered}</div>
  }
}

方法一:

只需在渲染之前将设置数组转换为组件数组:

const settings = {
        layout: [
            "panela",
            "panelb",
            "panelc"
        ]
    };

const panels = settings.layout.map(c => {
  switch (c) {
    case "panela": return { Component: PanelA, key: c };
    case "panelb": return { Component: PanelA, key: c };
    ...
  }
});

// Now use panels array to render:

class MyComponent extends React.Component {
  // ...
  renderComponentsInOrder() {
    return panels.map(({Component, key}) => (
      <Component key={key} {.../* some state*/} />
    ));
  }

  // ...
}

方法二:

只需创建一个映射表:

const settings = {
        layout: [
            "panela",
            "panelb",
            "panelc"
        ]
    };

const panelLookup = {
  "panela": PanelA,
  "panelb": PanelB,
   ...
};

// Now use lookup to render:
// Now use panels array to render:

class MyComponent extends React.Component {
  // ...
  renderComponentsInOrder() {
    return settings.layout.map(key => {
      const Component = panelLookup[key];
      return <Component key={key} {.../* some state*/} />;
    });
  }

  // ...
}