我创建了一个React组件,该组件呈现给定ID数组的一组子元素。id的数组保持在父组件的状态,然后我根据id运行一些ajax调用以获取要渲染的数据。所获取的数据在该状态下存储在单独的数据数组中。呈现的组件 将id用作key 。
id可以根据组件外部的操作而更改,因此我在组件上使用setState替换数组。 更新后的id状态可能包含与原始数组中相同的id。 同时,我清空“数据数组”,以便再次呈现所有内容。
当我这样做时,有时会收到密钥警告:
警告:flattenChildren(…):遇到两个具有相同密钥的孩子。子键必须是唯一的;当两个孩子共享一个密钥时,将仅使用第一个孩子。
新数组不包含任何重复项。那么为什么会发生这种情况,我该怎么做才能避免这种情况?
编辑:根据要求添加了一些代码。注意:我正在使用Infinite Scroll模块。这可能是原因吗?
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: [] });
我发现了自己的错误,这与React本身无关。这是在循环中缺少javascript闭包的经典案例。
由于重复的可能性,我将每个ajax响应都存储在movieId上的window.localStorage中。还是我想。
在React Inifinite Scroll中,通过调用loadMore函数依次绘制列表中的每个项目。在此函数中,我进行了ajax调用,并将结果存储在浏览器缓存中。代码看起来像这样:
var cachedValue = window.localStorage.getItem(String(movieId)); var cachedData = cachedValue ? JSON.parse(cachedValue) : cachedValue; if (cachedData != null) { comp.drawNextMovie(cachedData); } else { $.ajax( { type: "GET", url: this.state.movieUrl + movieId, contentType: "json", success: function (movieData) { window.localStorage.setItem(String(movieId), JSON.stringify(movieData)); comp.drawNextMovie(movieData); } }); }
你能发现错误吗?当ajax调用返回时,movieId不再是原来的样子。所以我最终用错误的id存储数据,并得到一些奇怪的React警告。因为这是在InfiniteScroll模块调用的loadMore函数内部完成的,所以我不知道此函数的作用域不正确。
我通过添加立即调用的函数expression来修复它。