Redux 不应该阻止重新渲染吗?
Shouldn't Redux prevent re-rendering?
我有一个显示多个 Item
组件的 List
组件。 List
从 Redux 存储中获取数据。
当商店更新时(例如因为我删除了一个项目),所有 Item
s 都会重新渲染。 这是为什么?
我知道我可以使用 shouldComponentUpdate()
来阻止新的渲染,但我认为 Redux 会在内部完成它。
List.js
import React, { PropTypes, Component } from 'react';
import { connect } from 'react-redux';
import Item from './Item';
class List extends Component {
render() {
const { items } = this.props;
return (
<div>
<h2>List</h2>
{items.map((item, index) => <Item key={index} name={item.name} />)}
</div>
);
}
}
const mapStateToProps = state => ({
items: state.items
});
export default connect(
mapStateToProps
)(List);
Item.js
import React, { PropTypes, Component } from 'react';
class Item extends Component {
render() {
console.log('Render', this.props.name); // The component is re-rendered even if the props didn't change
return (
<div>
{this.props.name}
</div>
);
}
}
Item.propTypes = {
name: PropTypes.string
};
export default Item;
{items.map((item, index) => <Item key={index} name={item.name} />)}
这一行总是在父组件中创建一个新数组,每次生成 'new' 个 Item 组件
一些现有技术(正如 Dan Abramov 喜欢说的那样):Redux 是一种状态管理工具。它提供了一个 HOC (connect
),但是那个 HOC 不负责组件管理。 Redux 不会以任何方式管理组件的生命周期:它提供了一种有效存储和查询应用程序所需数据的方法。它主要受 Om 的影响,Om 是通往 React 的 Clojurescript 桥梁。事实上,redux 中的 store
s 非常类似于 Clojure 中的 atom
数据类型。
现在,进入问题的核心——即使您的数据完全相同,即使您确实使用了shouldComponentUpdate
,您的组件也是仍然要重新渲染。原因是Array.prototype.map
总是在堆上产生一个新的对象。因此,它们在引用上并不相等。演示此概念的一些代码:
const myArr = [1, 2, 3]
const myArrCopy = myArr.map((n) => n);
myArr === myArrCopy // false
但是如果我们使用shallowEqual
,我们会得到不同的结果:
const myArr = [1, 2, 3]
const myArrCopy = myArr.map((n) => n);
React.addons.shallowCompare(myArr, myArrCopy); // true
这是为什么?这是因为 shallowCompare
检查 值是否相等 ,比较数组中的每个值。但是,shallowEquals
包含一个潜在的陷阱:
const myObject = { foo: 'bar' };
const myObject2 = { foo: 'baar' };
React.addons.shallowCompare(myObject, myObject2); // true
我们的两个对象不一样,但是 shallowCompare
returns true
因为它只比较其参数的 keys。如果这对您来说足够好,您可以简单地扩展 React.PureComponent
,它为您实现 shouldComponentUpdate
,并使用 shallowCompare
来计算 props
和 state
的相等性。
输入Immutable.js。这完全消除了 shallowCompare
的需要。考虑以下因素:
const myList = Immutable.List([1, 2, 3]);
const myListCopy = myList.map((n) => n);
myList.equals(myListCopy) // true
在内部,Immutable 共享数据,并且可以非常有效地比较数据结构以获得深度相等性。话虽这么说,但 Immutable 带来了权衡:数据结构变得更加不透明并且更难以调试。总而言之,我希望这能回答您的问题。 JSBin 在这里:https://jsbin.com/suhujalovi/edit?html,js,console
我有一个显示多个 Item
组件的 List
组件。 List
从 Redux 存储中获取数据。
当商店更新时(例如因为我删除了一个项目),所有 Item
s 都会重新渲染。 这是为什么?
我知道我可以使用 shouldComponentUpdate()
来阻止新的渲染,但我认为 Redux 会在内部完成它。
List.js
import React, { PropTypes, Component } from 'react';
import { connect } from 'react-redux';
import Item from './Item';
class List extends Component {
render() {
const { items } = this.props;
return (
<div>
<h2>List</h2>
{items.map((item, index) => <Item key={index} name={item.name} />)}
</div>
);
}
}
const mapStateToProps = state => ({
items: state.items
});
export default connect(
mapStateToProps
)(List);
Item.js
import React, { PropTypes, Component } from 'react';
class Item extends Component {
render() {
console.log('Render', this.props.name); // The component is re-rendered even if the props didn't change
return (
<div>
{this.props.name}
</div>
);
}
}
Item.propTypes = {
name: PropTypes.string
};
export default Item;
{items.map((item, index) => <Item key={index} name={item.name} />)}
这一行总是在父组件中创建一个新数组,每次生成 'new' 个 Item 组件
一些现有技术(正如 Dan Abramov 喜欢说的那样):Redux 是一种状态管理工具。它提供了一个 HOC (connect
),但是那个 HOC 不负责组件管理。 Redux 不会以任何方式管理组件的生命周期:它提供了一种有效存储和查询应用程序所需数据的方法。它主要受 Om 的影响,Om 是通往 React 的 Clojurescript 桥梁。事实上,redux 中的 store
s 非常类似于 Clojure 中的 atom
数据类型。
现在,进入问题的核心——即使您的数据完全相同,即使您确实使用了shouldComponentUpdate
,您的组件也是仍然要重新渲染。原因是Array.prototype.map
总是在堆上产生一个新的对象。因此,它们在引用上并不相等。演示此概念的一些代码:
const myArr = [1, 2, 3]
const myArrCopy = myArr.map((n) => n);
myArr === myArrCopy // false
但是如果我们使用shallowEqual
,我们会得到不同的结果:
const myArr = [1, 2, 3]
const myArrCopy = myArr.map((n) => n);
React.addons.shallowCompare(myArr, myArrCopy); // true
这是为什么?这是因为 shallowCompare
检查 值是否相等 ,比较数组中的每个值。但是,shallowEquals
包含一个潜在的陷阱:
const myObject = { foo: 'bar' };
const myObject2 = { foo: 'baar' };
React.addons.shallowCompare(myObject, myObject2); // true
我们的两个对象不一样,但是 shallowCompare
returns true
因为它只比较其参数的 keys。如果这对您来说足够好,您可以简单地扩展 React.PureComponent
,它为您实现 shouldComponentUpdate
,并使用 shallowCompare
来计算 props
和 state
的相等性。
输入Immutable.js。这完全消除了 shallowCompare
的需要。考虑以下因素:
const myList = Immutable.List([1, 2, 3]);
const myListCopy = myList.map((n) => n);
myList.equals(myListCopy) // true
在内部,Immutable 共享数据,并且可以非常有效地比较数据结构以获得深度相等性。话虽这么说,但 Immutable 带来了权衡:数据结构变得更加不透明并且更难以调试。总而言之,我希望这能回答您的问题。 JSBin 在这里:https://jsbin.com/suhujalovi/edit?html,js,console