【问题标题】:React component children detect if empty / null before renderReact 子组件在渲染前检测是否为空/null
【发布时间】:2019-03-22 15:52:58
【问题描述】:

“反应”:“16.8.4”

您好,有人知道如何检查(功能)组件中是否存在子组件(在渲染它们之前)

React.Children.count
React.Children.toArray(children)

不会工作

孩子们是$$typeof: Symbol(react.element)

代码示例是

function ContextMenuItems(): JSX.Element | null {
   if (no-items) return null;  
   ...
}

class ContextMenu extends React.Component {
   public render(): JSX.Element | null {
      if (this.props.children === null) { //ContextMenuItems empty check
        return null;
       }
       return <ContextMenu>{this.props.children}</ContextMenu>
   }
}

如有任何帮助,感谢您的想法

【问题讨论】:

  • 在那个问题中检查的是特定的孩子,这里我想检查孩子的数量
  • @James 除了对您添加的赏金的赞成答案之外,您还期待什么?您的问题仍然是旧版本的 react 吗?
  • 嗨,@user11243583,看看我的回答,我想这就是你要找的
  • 一开始我很难理解这里投票最高的答案。直到一分钱掉下来,我才明白children.type() 真的只是试图调用一个孩子的渲染函数。我写了一个 blog article 涵盖了这个用例,希望在解释事情方面做得更好。希望对您有所帮助。

标签: javascript reactjs


【解决方案1】:

解决方案一:

让孩子们type。如果Child 组件返回null,它将返回null

const isChildNull = children => {
  return Boolean(children.type()=== null);
};

解决方案 2:

使用ReactDOMServer.renderToStaticMarkup。它将jsx 元素转换为string。如果 children 返回 null 那么renderToStaticMarkup 将返回一个空字符串:

import ReactDOMServer from 'react-dom/server';

const isChildNull = children => {
  return !Boolean(ReactDOMServer.renderToStaticMarkup(children));
};

用法:

const Child = () => {
  return null;
};
    
const Parent = ({ children }) => {
  const isNull = isChildNull(children);
  if (isNull) {
     return "render null";
  }
  return <div>{children}</div>;
};
    
export default function App() {
   return (
     <Parent>
        <Child />
     </Parent>
   );
}

Working example using solution 1

【讨论】:

  • 在解决方案 1 中,type 不应该是函数,而是 children.type === null
  • @Cameron 使用类型作为函数的工作示例stackblitz.com/edit/react-ugqtgm
  • 常规 html 元素会出错,而 .type 对两者都有效。如果孩子是undefined
  • @Cameron 在这种情况下,您可以先检查 children 是否为 undefined/null 或定义默认值。
  • type 对于 HTML 元素是一个字符串,即。 “p”,“div”。在这种情况下,它是不可调用的。 type 用于功能组件只是渲染函数。当使用type() 作为函数时,实际上只是手动渲染它,这就是您可以查看它是否返回null 的方式。这不适用于经典组件,因为type 是构造函数,所以您需要调用new type().render()。如果组件依赖于 props,两者都不起作用,因为它们需要作为函数的参数进入。另外,跳过生命周期可能是个问题。
【解决方案2】:

您可以通过阅读 children 属性以及 React.Children.count 来检查组件是否有子组件,代码如下:

function ContextMenuItems({ children }): JSX.Element | null {
   if (!React.Children.count(children)) return null;
   ...
}

【讨论】:

  • 在创建 ContextMenu 之前检查在 ContextMenu
  • 当子组件返回null时,这不起作用。
  • @lissettdm 当子组件返回null时,不应该算作子组件吧?
  • @alextrastero 我同意你的观点,但在这种情况下,如果组件有一个返回 null 的子组件,则这一行 React.Children.count(children) 将等于 1。想法是检测该孩子是否返回 null,而不是计算孩子数
【解决方案3】:

除了其他解决方案,如果你想检查一个孩子是否是一个空字符串,你可以做以下测试:

!React.isValidElement(children) && children === ""

它帮助我做了一个辅助组件,如果作为子组件提供的组件是空字符串,它可以编写文本:

const EmptyTextHelper = ({ children }: { children?: React.ReactNode }) => !React.isValidElement(children) && children === "" ? (
<span className="italic">No text</span>) : (
<>{children}</>);

【讨论】:

    【解决方案4】:

    您可以在应用 React.Children.count as 之前添加 isValidElement 检查

    function getValidChildren(children) {
      return React.Children.toArray(children).filter((child) =>
        React.isValidElement(child)
      ) as React.ReactElement[]
    }
    
    function ContextMenuItems({ children }): JSX.Element | null {
       if (!React.Children.count(getValidChildren(children))) return null;
       ...
    }
    

    【讨论】:

    • 这将为字符串返回 false (这是一个有效的孩子)。对于一个空片段,它也会返回 true,我认为大多数人会认为它是一个空子。
    【解决方案5】:

    在您的父级渲染时,子级不会渲染;您只能访问描述它们的元素。因此,您可以检查元素本身是 null 还是空字符串,正如其他答案所描述的那样。但是,如果它是一个有效的元素,很遗憾,您无法看到子组件是否从其渲染中返回 null。

    要解决此问题,您可以手动渲染它,因为@lissettdm 有described。但请注意,它会渲染孩子两次;一次是手动的,一次是小时候正常的。并且尝试通过type() 进行渲染可能通常会起作用,但有caveats。这并不理想。

    通过 CSS 隐藏

    如果您只是希望避免在 DOM 中没有子级时在屏幕上显示父级;例如。您不想要一个空的上下文菜单,那么您可以考虑使用简单的 CSS 并使用 :empty selector 定位您的父级,以这种方式隐藏它。

    .hidden-if-empty:empty {
      display: none;
    }
    
    const ContextMenu = ({ children }) => {
      return <foo className="hidden-if-empty">{children}</foo>
    }
    

    通过 CSS 回退

    如果需要显示后备,可以使用CSS content

    或者,使用:only-child selector:

    .fallback {
      display: none;
    }
    .fallback-if-empty .fallback:only-child {
      display: block;
    }
    
    const ContextMenu = ({ children }) => (
      <foo className="fallback-if-empty">
        {children}
        <bar className="fallback">Nothing to see here!</bar>
      </foo>
    );
    

    【讨论】:

      猜你喜欢
      • 2020-10-15
      • 2017-01-25
      • 1970-01-01
      • 2018-10-07
      • 1970-01-01
      • 2018-07-26
      • 2020-05-11
      • 1970-01-01
      • 2021-05-18
      相关资源
      最近更新 更多