diff --git a/TODO/react-redux-optimization.md b/TODO/react-redux-optimization.md index 167f8fa515c..0e06839bd1c 100644 --- a/TODO/react-redux-optimization.md +++ b/TODO/react-redux-optimization.md @@ -1,26 +1,27 @@ -> * 原文地址:[Redux isn't slow, you're just doing it wrong - An optimization guide](http://reactrocket.com/post/react-redux-optimization/) +> * 原文地址:[Redux 并不慢,只是你使用姿势不对 —— 一份优化指南](http://reactrocket.com/post/react-redux-optimization/) > * 原文作者:[Julian Krispel](https://twitter.com/juliandoesstuff) > * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) > * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/TODO/react-redux-optimization.md](https://github.com/xitu/gold-miner/blob/master/TODO/react-redux-optimization.md) -> * 译者: -> * 校对者: +> * 译者:[reid3290](https://github.com/reid3290) +> * 校对者:[sunui](https://github.com/sunui),[xekri](https://github.com/xekri) -# Redux isn't slow, you're just doing it wrong - An optimization guide +# Redux 并不慢,只是你使用姿势不对 —— 一份优化指南 -It's not very obvious how to optimize react applications that use Redux. But it's actually fairly straightforward. Here's a short guide, along with a few examples. +如何优化使用了 Redux 的 React 应用不是那么显而易见的,但其实又是非常简单直接的。本文即是一份带有若干示例的简短指南。 -When optimizing applications that use Redux with react, I often hear people saying that Redux is slow. In 99% of cases, the cause for bad performance (this goes for any other framework) is linked to unnecessary rendering, since DOM updates are expensive! In this article, you’ll learn how to avoid unnecessary rendering when using Redux bindings for react. +在优化使用了 Redux 的 React 应用的时候,我经常听人说 Redux 很慢。其实在 99% 的情况下,性能低下都和不必要的渲染有关(这一论断也适用于其他框架),因为 DOM 更新的代价是昂贵的。通过本文,你将学会如何在使用 Redux 的 React 应用中避免不必要的渲染。 -Typically, to update react components whenever your Redux store updates, we use the [`connect`](https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options) higher order component from the [official react bindings for Redux](https://github.com/reactjs/react-redux). This is a function that wraps your component in another component, which subscribes to changes in the Redux store and renders itself and consequently it’s descendants whenever an update occurs. +一般来讲,要在 Redux store 更新的时候同步更新 React 组件,需要用到[ React 和 Redux 的官方绑定库](https://github.com/reactjs/react-redux)中的 [`connect`](https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options) 高阶组件。 +`connect` 是一个将你的组件进行包裹的函数,它返回一个高阶组件,该高阶组件会监听 Redux store,当有状态更新时就重新渲染自身及其后代组件。 -## A quick dive into react-redux, the official react bindings for Redux +## React 和 Redux 的官方绑定库 —— react-redux 快速入门 -The `connect` higher order component is actually already optimized. To understand how to best use it it’s best to understand how it works! +`connect` 高阶组件实际上已经被优化过了。为了理解如何更好地使用它,必须先理解它是如何工作的。 -Redux, as well as react-redux are actually quite small libraries so the source code isn’t impenetrable. I encourage people to read through the source code, or at least bits of it. If you want to go a step further, write your own implementation, it’ll give you thorough insight into why a library is designed the way it is. +实际上,Redux 和 react-redux 都是非常小的库,因此其源码也并非高深莫测。我鼓励人们通读源码,或者至少读一部分。如果你想更进一步的话,可以自己实现一个,这能让你深入理解为什么它要作如此设计。 -Without further ado, let’s dive a little into how the react bindings work. As we established, the central piece of the react bindings is the `connect` higher order component, this is it’s signature: +闲言少叙,让我们稍微深入地研究一下 react-redux 的工作机制。前面已经提过,react-redux 的核心是 `connect` 高阶组件,其函数签名如下: return function connect( mapStateToProps, @@ -38,14 +39,13 @@ Without further ado, let’s dive a little into how the react bindings work. As ... } +顺便说一下 —— 只有 `mapStateToProps` 这一个参数是必须的,而且大多数情况下只会用到前两个参数。此处我引用这个函数签名是为了阐明 react-redux 的工作机制。 -As a side note - The only mandatory argument is `mapStateToProps` and in most cases you will only need the first two arguments. However, I’m using the signature to here to illustrate how the react bindings work. +所有传给 `connect` 函数的参数都用于生成一个对象,该对象则会作为属性传给被包裹的组件。`mapStateToProps` 用于将 Redux store 的状态映射成一个对象,`mapDispatchToProps` 用于产生一个包含函数的对象 —— 这些函数一般都是动作生成器(action creators)。`mergeProps` 则接收 3 个参数:`stateProps`、`dispatchProps` 和 `ownProps`,前两个分别是 `mapStateToProps` 和 `mapDispatchToProps` 的返回结果,最后一个则是继承自组件本身的属性。默认情况下,`mergeProps` 会将上述参数简单地合并到一个对象中;但是你也可以传递一个函数给 `mergeProps`,`connect` 则会使用这个函数为被包裹的组件生成属性。 -All arguments passed into the `connect` function are used to generate an object, which is passed onto the wrapped component as props. `mapStateToProps` is used for mapping the state from your Redux store to an object, `mapDispatchToProps` is used to produce an object containing functions - typically those functions are action creators. Finally `mergeProps` takes three arguments `stateProps`, `dispatchProps` and `ownProps`. The first is the result of `mapStateToProps`, the second the result of `mapDispatchToProps` and the third argument is the props object that is inherited from the component itself. By default `mergeProps` simply combines those arguments into one object, but if you pass in a function for the `mergeProps` argument, `connect` will instead use that to generate the props for the wrapped component. +`connect` 函数的第四个参数是一个属性可选的对象,具体包含 5 个可选属性:一个布尔值 `pure` 以及其他四个用于决定组件是否需要重新渲染的函数(应当返回布尔值)。`pure` 默认为 true,如果设为 false,`connect` 高阶组件则会跳过所有的优化选项,而且那四个函数也就不起任何作用了。我个人认为不太可能有这类应用场景,但是如果你想关闭优化功能的话可以将其设为 false。 -The fourth argument of the `connect` function is an options object. This contains 5 options: `pure`, which can be either true or false as well as 4 functions (which should return a boolean) that determine whether to re-render the component or not. `pure` is by default set to true. If set to false, the `connect` hoc will skip any optimizations and the 4 functions in the options object will be irrelevant. I personally can’t think of a use-case for that, but the option to set it to false is available if you prefer to turn off optimization. - -The object that our `mergeProps` function produces is compared with the last props object. If our `connect` HOC thinks the props object has changed, the component will re-render. To understand how the library decides whether there has been a change we can look at the [`shallowEqual` function](https://github.com/reactjs/react-redux/blob/master/src/utils/shallowEqual.js). If the function returns true, the component won’t re-render, if it returns false it will re-render. `shallowEqual` performs this comparison. Below you’ll see part of the `shallowEqual` method, which tells you all you need to know: +`mergeProps` 返回的对象会和上一个属性对象作比较,如果 `connect` 高阶组件认为属性对象所有改变的话就会重新渲染组件。为了理解 `react-redux` 是如何判断属性是否有变化的,请参考 [`shallowEqual` 函数](https://github.com/reactjs/react-redux/blob/master/src/utils/shallowEqual.js)。如果该函数返回 true,则组件不会渲染;反之,组件将会重新渲染。`shallowEqual` 负责进行属性对象的比较,下文是其部分代码,基本表明了其工作原理: for (let i = 0; i < keysA.length; i++) { if (!hasOwn.call(objB, keysA[i]) || @@ -54,20 +54,19 @@ The object that our `mergeProps` function produces is compared with the last pro } } +概括来讲,这段代码做了这些工作: -To summarize, this is what the above code does: - -It loops over the keys in object a and checks if object B owns the same property. Then it checks if the property (with the same name) from object A equals the one from object B. If only one of the comparisons returns false, the objects will be deemed unequal and a re-render will occur. +遍历对象 A 中的所有属性,检查对象 B 中是否存在同名属性。然后检查 A 和 B 同名属性的属性值是否相等。如果这些检查有一个返回 false,则对象 A 和 B 便被认为是不等的,组件也就会重新渲染。 -This leads us to one golden rule: +这引出一条黄金法则: -## Give your component only the data it needs to render. +## 只给组件传递其渲染所必须的数据 -This is quite vague, so let’s elaborate with a bunch of practical examples. +这可能有点难以理解,所以让我们结合一些例子来细细分析一下。 -### Split up your connected components +### 将和 Redux 有连接的组件拆分开来 -I’ve seen people do this. Subscribing a container component to a bunch of state and passing everything down via props. +我见过很多人这样做:用一个容器组件监听一大堆状态,然后通过属性传递下去。 const BigComponent = ({ a, b, c, d }) => (