【问题标题】:React: avoid rendering component's root DOM element if DOM children are emptyReact:如果 DOM 子项为空,则避免渲染组件的根 DOM 元素
【发布时间】:2019-05-07 15:13:14
【问题描述】:

我有一个接收children 的 React 组件,将它们包装在一个 DOM 元素中:

const MyComponent = ({ children }) => <div>{children}</div>;

children 解析为 0 个 DOM 节点时,我想跳过渲染容器 DOM 元素(本例中为 div)。

(这是因为容器 DOM 元素可能会在元素为空时提供我们不想要/不需要的语义或样式。)

例如

const MySubComponent = () => null;

declare const maybeChild: string | undefined;
const el = <MySubComponent />;

const el = (
  <MyComponent>
    {maybeChild}
    {el}
  </MyComponent>
)

在本例中,生成的 DOM 将是 &lt;div&gt;&lt;/div&gt;

大概我应该通过计算 MyComponent 中的 DOM 子项的数量来做到这一点(使用此作为渲染内容的条件),但似乎没有一种简单的方法可以做这个。 (React.Children API 指的是 React 节点树中的子节点,而不是 DOM,因此在这种情况下这似乎没有帮助。)

我知道的一个解决方案是确保 React 节点到 DOM 节点的 1:1 映射。然而,这似乎不切实际,因为组件内部通常具有渲染条件。

【问题讨论】:

  • 在渲染组件之前返回 null 怎么样?
  • 问题在于,即使所有子元素都渲染为空,React 元素仍然存在,并且可以更新以渲染某些内容而无需重新渲染父元素。
  • 没有直接的方法可以做到这一点。您将需要渲染孩子并确保有 DOM 元素。为什么空 div 有问题?这可能是 XY 问题。
  • @OliverJosephAsh 这就是我所说的 XY 问题。使用 :empty 作为样式。这比直接访问 DOM 要简单得多。
  • 我不希望重新设计它会破坏封装——它会改变职责的组织方式。某种数据驱动子组件是否呈现任何内容。该数据还应确定是否呈现父级。大概子组件正在获取数据和渲染。如果子组件变得纯粹是展示性的,您可以将当前父组件包装在获取数据的东西中,决定是否需要渲染,如果需要,然后将数据传递给子组件。

标签: reactjs


【解决方案1】:

这个问题感觉应该重新设计。我知道这不是一个令人满意的解决方案,但是孩子可能包含数百个 DOM 节点,并且它们的深度可能很密集。开始这件事并不谨慎。此外,在向其父级公开子级的实现细节时,应该普遍犹豫。如果您真的想这样做,我会关注React refs,但它们仅在初始渲染后可用。

【讨论】:

    【解决方案2】:

    您应该使用React.Fragment 并检查孩子。

    例如

    const MyComponent = ({ children }) => <React.Fragment>
        {children ? 
            <div>{children}</div> 
            : 
            null
        }
    </React.Fragment>;
    

    *我注意到你使用 typescript,我对 typescript 和如何检查不太了解,但如果你按照逻辑,我认为你可以使用 typescript 解决它

    编辑:

    所以你需要做的是检查孩子是否是一个有效的 React 元素。

    检查您是否需要React.isValidElement

    这是检查它是否有效的方法

    const MyComponent = ({ children }) => {
      let valid = true;
      if (Array.isArray(children)) {
        for (let i = 0; i < children.length; i++) {
          if (!isValidElement(children[i])) {
            valid = false;
          }
        }
      } else {
        valid = isValidElement(children);
      }
      if (valid) {
        return <div>{children}</div>;
      }
      return null;
    };
    

    我创建了一个codesandbox 来检查是否有效。

    使用React.isValidElement 你可以进行其他检查(可能只渲染有效的 React 组件)

    再一次,很抱歉没有在打字稿中给出答案。

    编辑:

    如果这个解决方案仍然不能令人满意,因为元素可以渲染null,那么你应该看看lluisrojass的解释。

    【讨论】:

    • 在我上面的例子中,children 将是真实的,所以不幸的是这不会完成这项工作。即使你React.Children.count(children),它也会是2
    • @OliverJosephAsh 刚刚编辑,现在我认为这可以解决您的问题
    • isValidElement 仍将返回 true 用于不呈现任何内容的组件。例如。按照我原来的例子,&lt;MySubComponent /&gt;
    • 那是因为渲染null是有效的。所以你只想渲染 html(或组件),不允许它渲染null
    猜你喜欢
    • 2023-03-19
    • 2020-03-30
    • 1970-01-01
    • 1970-01-01
    • 2017-10-09
    • 2020-11-04
    • 2021-11-30
    • 2020-03-27
    • 2019-01-15
    相关资源
    最近更新 更多