【问题标题】:React parent component check if child will render反应父组件检查子组件是否会渲染
【发布时间】:2018-07-26 07:33:50
【问题描述】:

我有一个子组件,它依赖于它的某些道具最终会渲染或不渲染某些东西。孩子的渲染函数看起来像这样:

render() {
  if (props.a == 'foo' && props.b == 'bar') {
    return (<p> Hey There </p>);
  } else if {props.a == 'z') {
    return (<p> Hey There </p>);
  } // more conditions
  } else {
    return null
  }
}

在父组件中,我正在渲染几个子组件,我需要知道其中有多少会渲染,因为根据这个数字,我会做些什么或不做些什么。我不想重复从孩子到父母的条件逻辑,但我不知道如何从父母那里知道孩子是否会渲染。

【问题讨论】:

  • 如果父级渲染,所有子级都将渲染,除非他们中的一些已经实现了返回 false 的 shouldcomponentUpdate 或者如果他们是 PureComponent 在这种情况下在他们的状态和道具之间进行浅比较
  • The render function looks something like this , 渲染 what , child 或 parent 的函数。

标签: javascript reactjs


【解决方案1】:

您正在尝试做的是 React 中的一种反模式。 如果我理解您的问题,子渲染输出会影响其父渲染输出,这可能会让您陷入渲染循环。

我建议您使子组件尽可能简单,并将条件逻辑提升到父组件,这样您就可以计算要渲染的子组件数量。

如果我的问题有误,请告诉我。

【讨论】:

  • 但是这种逻辑是针对孩子们的。
【解决方案2】:

虽然我同意perpetualjourney的回答,但我想我可以给你一个数孩子的可能性。

最简单的方法是先将子项的渲染保存到一个变量中,然后再渲染该结果。

var kids = this.props.items.map( (k, i) => <Kid condition={k} key={i} /> );
var totalKids = kids.reduce( (k, i) => k + (i.type( i.props ) ? 1 : 0), 0);

现在,这会渲染你的孩子两次,所以当你已经有一个性能很重的方法时它不是最好的

const Kid = ({ condition }) => condition % 3 === 0 ? <h1>{ condition }</h1> : null;

class ConditionalKids extends React.Component {
  render() {
    var kids = this.props.items.map( (k, i) => <Kid condition={k} key={i} /> );
    var totalKids = kids.reduce( (k, i) => k + (i.type( i.props ) ? 1 : 0), 0);
    return <div>
      <p>Rendered in total { totalKids }</p>
      { kids }
    </div>;
  }
}

const items = [...new Array(5)].map( i => parseInt( Math.random() * 10 ) );
console.log( items );

const target = document.querySelector('#container');
ReactDOM.render( <ConditionalKids items={items} />, target );
<script id="react" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.2/react.js"></script>
<script id="react-dom" src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/15.6.2/react-dom.js"></script>
<div id="container"></div>

【讨论】:

  • Icepickle,这对我不起作用。你确定:var kids = this.props.items.map( (k, i) =&gt; &lt;Kid condition={k} key={i} /&gt; ); 渲染孩子吗?它不适合我,它只是初始化组件,但它不渲染。当我执行{kids} 时,它会渲染它们。我在小子的render方法里放了一个控制台日志,两次都没看到。
  • @HommerSmith 会,但不是在映射时,它会在 reduce 和实际渲染期间
  • 为什么要在reduce中这样做?您在使其渲染的 reduce 中做了什么?是因为你调用 i.props 吗?还是……?
  • @HommerSmith 这是因为对i.type( i.props ) 的调用将调用演示组件,因此我们可以看到它的输出是什么
  • 哦,明白了。你是怎么知道的? i.typei.props 到底是什么?
【解决方案3】:

处理此问题的一种方法是使用state

在这个CodeSandbox example 中,我使用if/else 逻辑来更新组件的state。这是在 componentWillReceiveProps 生命周期方法中完成的。

您的render 方法被简化为switch 语句。

如果您想根据您拥有的 if/else 逻辑调用命令式 API,您可以在您的 componentDidUpdate 生命周期方法中执行此操作。这也被简化为switch 语句。

【讨论】:

    【解决方案4】:

    这是一个非常相关的问题,它会影响任何复杂的应用程序。不幸的是,目前还没有明确的方法可以使用 React 对此进行建模。我已经做了很多 React 并且会推荐 @perpetualjourney 所说的:将逻辑提升到一个共同的父级。有时您需要将其向上移动,但不要乱用React.Children.mapReact.Context,因为它们会在组件之间创建依赖关系,并且如果需要,您将更难移动它们。

    const hasA = computeHasA({ ... });
    const hasB = computeHasB({ ... });
    const hasAny = hasA || hasB;
    
    if (hasAny) {
      return (
        <Tabs>
          {hasA && <Tab title="A">Some content</Tab>}
          {hasB && <Tab title="B">Another content</Tab>}
        </Tabs>
    
      );
    }
    

    当你真的无法向上移动逻辑时,例如,如果孩子们发出网络请求,这可能是一个边缘情况,我建议传递一个用于报告他们是否有内容的道具并存储它进入父母的状态:

    const [numberOfRenderedChildren, setNumberOfRenderedChildren] = useState(0);
    
    const incrementNumberOfRenderedChildren = () => {
      // Use a callback to prevent race conditions
      setNumberOfRenderedChildren(prevValue => prevValue + 1);
    };
    
    
    return (
      <MyContainer isVisible={numberOfRenderedChildren > 0}>
        {items.map(item => (
          <ComplexChild
            key={item.id}
            // Avoid spreading props like ...item. It breaks semantics
            item={item}
            reportHasContent={incrementNumberOfRenderedChildren}
          />
        )}
      </MyContainer>
    );
    

    如果您需要加载器和错误消息,它可能会变得更加复杂,但是我会触发父级中的所有请求。尽量保持简单,易于阅读,即使这意味着更冗长。几周后您需要返回这些文件时,您不会后悔。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-15
      • 2019-06-20
      • 1970-01-01
      • 1970-01-01
      • 2018-10-07
      • 1970-01-01
      • 1970-01-01
      • 2020-02-13
      相关资源
      最近更新 更多