作为道具传递的 Array.prototype.filter() 会触发子组件重新渲染,但 Array.prototype.sort() 不会



我正在使用ReactJS,并希望将过滤和排序的数组传递到组件的props中,如下面的代码片段所示:

<component arrayData={justAnArray
.filter(//some condition here)
.sort(//sorting function here)} />

该组件旨在在收到的道具与之前的道具不同时更新其状态,如下所示:

componentWillReceiveProps(nextProps){
if (this.props.arrayData != nextProps.arrayData){
this.setState({ // some state here })
}
}

这导致了错误

超出最大更新深度。当组件在 componentWillUpdate 或 componentDidUpdate 中重复调用 setState 时,可能会发生这种情况。React 限制嵌套更新的数量以防止无限循环。

在故障排除过程中,我发现如果仅使用 .sort() 传递组件不会导致任何错误,即

<component arrayData={justAnArray
.sort(//sorting function here)} />

但是如果只传递 .filter,则会出现错误,即

<component arrayData={justAnArray
.filter(//some condition here)/>

这很奇怪,所以我开始研究 Array.prototype.sort() 和 Array.prototype.filter() 之间的区别。我发现 .filter() 返回一个新数组,而 .sort() 似乎返回原始数组,因为排序已经就地完成。

这可能是导致错误的原因吗?如果是,我应该怎么做才能防止此错误?

谢谢。


编辑:根据Kalidindi的要求@Nandu,我正在发布相关代码:

class Pagination extends Component {
constructor(props) {
super(props);
this.state = {
pager: {}
};
}
componentWillMount() {
// set page if items array isn't empty
if (this.props.items && this.props.items.length) {
this.setPage(this.props.initialPage);
}
}
componentWillReceiveProps(nextProps) {
// reset page if items array has changed
if (this.props.items != nextProps.items) {
this.setPage(this.props.initialPage);
}
}
setPage(page) {
var items = this.props.items;
var pager = this.state.pager;
if (page < 1 || page > pager.totalPages) {
return;
}
// get new pager object for specified page
pager = this.getPager(items.length, page, 3);
// get new page of items from items array
var pageOfItems = items.slice(pager.startIndex, pager.endIndex + 1);
// update state
this.state.pager = pager;
// call change page function in parent component
this.props.onChangePage(pageOfItems);
}
render() {
return( //render )
}
}
export default Pagination;

这基本上是这个在线 ReactJS 分页示例的 React Native 版本。

这就是我使用该组件的方式:

const someData= [{id: 1, title: 'a'}, 
{id: 2, title: 'b'}, 
{id: 3, title: 'c'}, 
{id: 4, title: 'd'}, 
{id: 5, title: 'e'},];

class SomePage extends Component {
constructor(){
super();
this.state={
pageOfItems: [],
}
this.onChangePage = this.onChangePage.bind(this);
this.filterAndSort = this.filterAndSort.bind(this);
}

filterItems = (items) => {
return items.filter(this.handleFilter);
}
sortItems = (items) => {
return items.sort(this.handleSort);
}
filterAndSort = () =>{
return this.sortItems(this.filterItems(someData));
}

onChangePage = (pageOfItems) =>{
//update state with new page of alignItems
this.setState({ pageOfItems: pageOfItems });
}

render(){

return(
<ScrollView style={{flex: 1}}>
{this.state.pageOfItems
.map((item) => {
return(
<box item={item} />
//just a component that displays the objects inside the arrays
)
})
}
</ScrollView>
<Pagination items={this.filterAndSort()} onChangePage={this.onChangePage} />
)
}

export default SomePage;


编辑2:

仅供其他人参考,这个问题的答案不是像我那样直接使用 '===' 比较数组。欲了解更多信息,请参阅@Nandu Kalidindi的回答。

  1. 无需setStatecomponentWillReceiveProps,单纯的赋值就足够了。这不是无限循环的原因,而只是一种很好的做法。

  2. 永远不要比较这样的数组。[1] == [1] is always false.要么使用JSON.stringify要么使用这种方法 如何在 JavaScript 中比较数组?

  3. 现在,filter+sort不起作用而不是仅sort的原因是因为filter创建了一个新数组,这意味着一个新的引用,其中sort返回相同的引用

在此处查看差异。

k = [1, 2, 3, 4]
r = k.sort()
console.log(k === r)
//TRUE
r = k.filter(elem => true).sort()
console.log(k === r)
// FALSE

因此,当您使用filter+sort时,无论您输入的条件如何,您的组件都会不断设置状态,而sort期间它始终相等,并且状态更新永远不会发生。

修改狙击手,如下所示

componentWillReceiveProps(nextProps){
if (JSON.stringify(this.props.arrayData) != JSON.stringify(nextProps.arrayData)){
this.state.arrayData = nextProps.arrayData;
}
}

现在,为什么你的组件无限地重新渲染是另一个谜,你必须在你的componentWillUpdateshouldComponentUpdate钩子中设置状态。这只是我的猜测。这就是为什么我建议你发布那里的所有相关代码。

相关内容

  • 没有找到相关文章