Redux 不应该阻止重新渲染吗?

IT技术 reactjs redux react-redux
2021-05-02 08:21:55

我有一个List显示多个Item组件的组件。List从 Redux 存储中获取其数据。

当商店更新时(例如因为我删除了一个项目),所有Items 都会重新渲染。这是为什么?

我知道我可以shouldComponentUpdate()用来阻止新的渲染,但我认为 Redux 会在内部完成。

列表.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);

项目.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;
2个回答

一点现有技术(正如 Dan Abramov 喜欢说的):Redux 是一种状态管理工具。它提供了一个 HOC( connect),但该 HOC不负责组件管理Redux 不会以任何方式管理组件的生命周期:它提供了一种有效存储和查询应用程序所需数据的方法。它很大程度上受到 Om 的影响,Om 是连接 React 的 Clojurescript 桥梁。事实上,storeredux 中的 s 非常类似于atomClojure 中数据类型。

现在,进入问题的核心——即使您的数据完全相同,即使您确实使用了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返回,true因为它只比较其参数如果这对您来说足够好,您可以简单地扩展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

{items.map((item, index) => <Item key={index} name={item.name} />)}

这一行总是在父组件中创建一个新的数组,每次都生成“新”的 Item 组件