我创建了一个React组件,它给出了一组给定一组id的子元素 . id数组保持在父组件的状态,然后我根据id运行一些ajax调用来获取要呈现的数据 . 获取的数据存储在该状态的单独数据阵列中 . 呈现的组件使用id作为键 .
id可以根据组件外部的操作进行更改,因此我在组件上使用setState来替换数组 . 更新的id-state可能包含一些与原始数组中相同的ID . 同时我清空'data array',以便再次渲染所有内容 .
当我这样做时,我有时会得到关键警告:
警告:flattenChildren(...):遇到两个孩子用同一把钥匙 . 子键必须是唯一的;当两个孩子共用一把钥匙时,只会使用第一个孩子 .
新数组不包含任何重复项 . 那么为什么会发生这种情况,我该怎么做才能避免这种情况呢?
编辑:按要求添加了一些代码 . 注意:我使用的是Infinite Scroll module . 这会导致它吗?
初始状态:
getInitialState: function() {
return {
hasMore: true,
num: 0,
movieIds: this.props.movieIds,
movies: []
};
},
渲染功能:
render: function() {
var InfiniteScroll = React.addons.InfiniteScroll;
return (
<InfiniteScroll
pageStart={0}
loadMore={this.loadMore}
threshold='20'
hasMore={this.state.hasMore}>
<ul className="movieList">
{this.state.movies}
</ul>
</InfiniteScroll>
);
}
简化加载更多:
comp = this;
$.ajax( {
url: url,
contentType: "json",
success: function (data) {
var m = createMovieLi(data);
var updatedMovies = comp.state.movies;
updatedMovies[num] = m;
comp.setState({movies: updatedMovies});
}
});
最后在组件外部进行更新时:
movieBox.setState({
hasMore: true,
num: 0,
movieIds: filteredIds,
movies: []
});
2 回答
我弄清楚了我的错误,它与React本身无关 . 这是missing javascript closure inside a loop的经典案例 .
由于重复的可能性,我在movieId上的window.localStorage中存储了每个ajax响应 . 或者我想 .
在React Inifinite Scroll中,列表中的每个项目都是通过调用loadMore函数顺序绘制的 . 在这个函数里面,我做了我的ajax调用,并将结果存储在浏览器缓存中 . 代码看起来像这样:
你能发现错误吗?当ajax-call返回时,movieId不再是什么了 . 所以我最终以错误的id存储数据,并得到一些奇怪的React警告作为回报 . 因为这是在InfiniteScroll-module调用的loadMore函数内部完成的,所以我不知道这个函数没有正确确定范围 .
我通过添加Immediately-invoked function expression来修复它 .
我不会将后端的ID用作React中的关键属性 . 如果你这样做,你依赖的是一些离你的组件有点远的逻辑,以确保你的密钥是唯一的 . 如果它们的键不是唯一的,那么你可以打破react的渲染,这一点非常重要 .
这就是为什么你应该坚持在for循环中使用索引或类似于设置键属性 . 这样你就知道它们永远不会是非唯一的,而且这是最简单的方法 .
如果不确切知道你的ID是如何工作的,那么's impossible to say what'会导致非唯一冲突 . 但是,由于
key
只是为了让React能够正确地识别元素,而不是其他任何东西,因此除了简单的计数或索引之外,它不是真的有意义 .