何时使用React createFragment?

时间:2015-10-07 21:32:04

标签: reactjs react-native

我在React Native中呈现ListView,设法修复此React警告,但我不明白它是如何以及为什么有效:

  

警告:任何对键控对象的使用都应该在作为子进行传递之前包装在React.addons.createFragment(object)中。

// This array generates React Fragment warning.
var data1 = [{name: "bob"}, {name:"john"}]

// This array works, no warnings.
var data2 = [React.addons.createFragment({name: "bob"}),
             React.addons.createFragment({name: "john"})]

// This also works, no warnings.
var data3 = ["bob", "john"]

class Listings extends React.Component {
  constructor(props) {
    super(props)
    ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2})

    this.state = {
      dataSource: ds.cloneWithRows(data),
    }
  }
  render() {
    return (
       <ListView
         dataSource={this.state.dataSource} 
         renderRow={(rowData) => <Text>{rowData}</Text>} />
    )
  }
}

什么是反应片段? React什么时候需要?为什么键控对象会导致此警告?

2 个答案:

答案 0 :(得分:15)

我将我的答案分为两部分,以涵盖我在你的问题中看到的两个要点。

第1节:什么是反应片段?

为了解释 React Fragment 是什么,我们需要退一步讨论 React Keys

帮助React识别哪些项已更改,已添加或已删除。它们应该被赋予数组中的元素,以赋予元素稳定的标识(唯一性)。

选择密钥的最佳方法是使用在其兄弟姐妹中唯一标识列表项的字符串。大多数情况下,您会使用数据中的ID作为键。这是一个实际的例子:

render() {
    const todoItems = todos.map((todo) =>
      <li key={todo.id}>
        {todo.text}
      </li>
    );

    return todoItems;
}

重要的是要注意todoItems实际上是一个<li>元素数组。

知道这一点,让我们继续讨论您在用例中收到警告的原因。

在大多数情况下,您可以使用key道具来指定从渲染中返回的元素上的键,就像上面的示例一样。但是,在一种情况下会出现这种情况:如果您有两组需要重新排序的子项,则无法在不添加包装元素的情况下在每个组上放置一个键。

以下是recently updated React docs

中的经典示例
function Swapper(props) {
  let children;
  if (props.swapped) {
    children = [props.rightChildren, props.leftChildren];
  } else {
    children = [props.leftChildren, props.rightChildren];
  }
  return <div>{children}</div>;
}

当您更改swapped道具时,孩子们将卸下并重新安装,因为两组孩子上没有标记任何钥匙。

要解决此问题,您可以使用createFragment加载项为子集提供密钥。 Follow the enhanced example, using the createFragment here

第2节:但是为什么要收到此警告?

无论如何,你得到错误的错误仅仅是因为你试图将一个JavaScript对象(而不是JSX元素或字符串)插入某个JSX中。

虽然错误消息建议使用createFragment来解决这个问题,但原因是你将一个变量插入到一个不是字符串或JSX元素的JSX中,但实际上是其他类型的对象!

在您的用例中出现这种误导性警告,不是吗? : - )

答案 1 :(得分:0)

您可以通过以下方式从“反应”中导入片段:

import React, { Fragment } from "react";

然后将渲染功能更新为:

render() {
    return (
       <ListView
         dataSource={this.state.dataSource} 
         renderRow={(rowData) => {
                               <Fragment key={passsKey}>
                                  <Text>{rowData}</Text>
                               </Fragment>
                             }} 
       />
 )}