反应 - 装饰儿童和处理钥匙

时间:2017-06-15 12:27:55

标签: reactjs

我正在写一个装饰一些孩子的小组件。鉴于以下示例:



const Child = props => <div>{props.name}</div>;
const Parent = props => {
  let wrappedChildren = React.Children.map(props.children, c => {
     return (<Decorator key={c.key}>
       {c}
     </Decorator>);
  });

  return (<div>
    {wrappedChildren}
  </div>);
}
const Consumer = props => {
     let children = [0, 1, 2].map(num => {
       return <Child key={num} name={num} />;
     });
    return <Parent>{children}</Parent>;
});
&#13;
&#13;
&#13;

在这段代码中,我想要带走每个孩子并用一些包装容器或某些行为来装饰它。忘记可能只有一个孩子的那一刻,我需要给每个实例一个密钥。

目前,我假设每个孩子都有一把不太棒的钥匙,把它从孩子身上移开并直接应用于装饰师。

这是&#34;正确&#34;这样做的方式?还有更好的方法吗?

3 个答案:

答案 0 :(得分:2)

这适用于当前版本的React,15.6.1(也可能与之前的版本一样)。但是,有一个更好的方法可以通过一个小的调整来实现你的目标,这可以将提升委托给一个道具,而不是直接使用key

原因是密钥的概念是在组件创建之前由React内部控制的东西,因此它属于实现细节类别,结果是React的未来版本可能会破坏您的代码注意到它。

相反,您可以在Child组件上使用道具,例如id,基于您假设每个孩子确实具有某种独特价值。您的代码将导致:

const Child = props => <div>{props.name}</div>;

const Parent = props => {
  return React.Children.map(props.children, c => {
     return (<Decorator key={c.props.id}>
       {c}
     </Decorator>);
  });

  return (<div>
    {wrappedChildren}
  </div>);
}

const Consumer = props => {
     let children = [0, 1, 2].map(num => {
       return <Child id={num} name={num} />;
     });
    return <Parent>{children}</Parent>;
});

如果您有一个更复杂的结构并且想要避免单独传递道具,那么父组件应该负责为子项生成唯一ID。您可以按照此回答https://stackoverflow.com/a/29466744/4642844中解释的提示进行操作。

这些是我要遵循的步骤:

  • 实现您自己的实用程序功能或使用现有的浏览器库生成唯一ID。
  • componentWillMount组件中实施Parent以创建一系列唯一ID。您可以使用内部成员类变量而不是本地state。它会是这样的:

    componentWillMount() {
      this.uuids = React.Children.map(() => uuid());  
    }
    
  • Parent渲染中,按以下方式将每个键分配给装饰器组件。

     render() {
       return React.Children.map(props.children, (c, i) => {
         return (<Decorator key={this.uuids[i]}>
           {c}
         </Decorator>);
       });
     }
    

一些有用的链接:

http://mxstbr.blog/2017/02/react-children-deepdive/

https://medium.com/@dan_abramov/react-components-elements-and-instances-90800811f8ca

答案 1 :(得分:1)

我认为你的方法很好。而你确实需要顶层的钥匙。使用孩子的钥匙(如果有的话)。如果没有,请回到index,正如React建议的那样:

  

当您没有渲染项目的稳定ID时,您可以将项目索引用作关键作为最后的手段。

请注意:

  

如果项目可以重新排序,我们建议不要使用密钥索引,因为这样会很慢。

来源:React Docs about keys

const Child = props => <div>{props.name}</div>;
const Parent = props => {
  let wrappedChildren = React.Children.map(props.children, (c, i) => {
    const key = c.key ? `key-${c.key}` : `index-${i}`
    return (
      <Decorator key={key}>
        {c}
      </Decorator>
    );
  });

  return (
    <div>
      {wrappedChildren}
    </div>
  );
};
const Consumer = () => {
  let children = [ 0, 1, 2 ].map(num => {
    return <Child key={num} name={num} />;
  });
  return <Parent>{children}</Parent>;
};

答案 2 :(得分:-1)

Javascript Array.map(fn)实际上将3个参数传递给fn秒作为索引。那么,你需要做的是: let wrappedChildren = props.children.map((c, i) => <Decorator key={i}>{c}</Decorator>);