了解 Redux 的基本实现 | prevState 是如何使用的?

Understanding a basic implementation of Redux | how is prevState used?

我正在查看 this article 中 redux 的超级基本实现示例。除了 dispatch 使用 prevState 的地方,我理解它。首先这个函数从哪里获得prevState?这与计数器需要的实际状态有什么关系?它是否在名为 prevState 的状态中隐式设置了另一个值?我只是很难理解状态实际上是如何传递给调度然后通过 prevState 反击的。我认为这可能是我还没有掌握的函数式编程思想。感谢您帮助我理解!

import React, { Component } from 'react';

const counter = (state = { value: 0 }, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { value: state.value + 1 };
    case 'DECREMENT':
      return { value: state.value - 1 };
    default:
      return state;
  }
}

class Counter extends Component {
  state = counter(undefined, {});
  
  dispatch(action) {
    this.setState(prevState => counter(prevState, action));
  }

  increment = () => {
    this.dispatch({ type: 'INCREMENT' });
  };

  decrement = () => {
    this.dispatch({ type: 'DECREMENT' });
  };
  
  render() {
    return (
      <div>
        {this.state.value}
        <button onClick={this.increment}>+</button>
        <button onClick={this.decrement}>-</button>
      </div>
    )
  }
}

prevState 在这种情况下是实际的当前状态。它不是时光倒流,它只是 returns 你当前的状态,它将被用来构建一个新的状态——因为在 Redux 和 React 的概念中,状态是 immutable,这意味着它永远不会被修改——当你发送新的动作并用你的减速器处理它时——你正在创建全新的对象(状态)。

React.Component.prototype.setState

React 的 setState 方法在这里负责 prevState不是 redux,只是为了清楚。

让我们看看如何使用setState。我们有 3 个选项 ...

  1. setState(nextState) - 只需传递下一个状态,React 就会相应地更新组件 state
  2. setState(nextState, callback) – 可选地指定一个回调,一旦组件被重新渲染就会调用 – React 组件将在 state 更新时重新渲染 – 注意:React 文档通常建议使用componentDidUpdate 生命周期方法。
  3. setState((prevState, props) => nextState) – 调用一个方便绑定 prevStateprops 标识符的函数,以便我们手动更新我们的状态。预计我们提供的功能 return 是下一个状态

所以你有这个

this.setState(prevState => counter(prevState, action));

如果不是很明显,您提供的代码示例使用的是 #3。因此,第一个参数 prevState 将由 React 提供,即组件的 current 状态。第二个参数 props 没有在这里使用,所以我们将忽略它(一般的想法是你可以使用道具来更新你的状态)。


什么是prevState

prevState到底是什么?好吧,我们确定它是您组件的当前状态,我们之前在 Counter 中将其初始化为

state = counter(undefined, {});
// => { value: 0 }

所以当我们派发一个 INCREMENT 时,我们会得到类似

的东西
this.setState(prevState => counter({value: 0}, {type: 'INCREMENT'})

在这种情况下 counter(减速器)将 return

{value: 1}

这个 return 值是组件下一个 状态


重复申请setState

当然,如果我们再次INCREMENT,我们会得到类似

的东西
this.setState(prevState => counter({value: 1}, {type: 'INCREMENT'})

其中 counter 会 return

{value: 2}

成为组件的下一个状态

等等..


"Where is line between React and Redux?"

首先,特定于 React 的代码是 import 和扩展 Component.

Counter class

"But what is the other code (counter) then?"

关于 redux 的最酷的事情之一是它的 无状态 – Redux 仅作为模式存在于此代码示例中。没有使用 reduxreact-reduximport。 Redux 在这里更多地用作 redux idea/philosophy 的实现——它是围绕单向数据流和可组合的 reducer 的思想构建的。

"What is a reducer?"

reducer 只是一个函数,当应用于状态和动作时,returns 一个 new 状态。

当然,redux 库包含一些有用的实用程序,可以更轻松地在您的应用程序中实现 Redux 的模式——但实际上,它们都是非常简单的功能。事实上,Redux 的创建者 Dan Abramov 有一个关于 egghead 的 awesome(免费)系列,Getting Started with Redux 向您展示了 Redux 是如何工作的,一个接一个。在我看来,它是有史以来最好的编码视频系列之一,涉及 任何 主题。

首先,请注意 Class Counter 扩展自 React 的 Component 类型。正因为如此它会继承一堆属性和方法,其中之一就是setState.

我们从React documentation for setState可以看出它有两个参数:

setState(nextState, callback)

但细则中是这样写的:"The first argument can be an object (containing zero or more keys to update) or a function (of state and props) that returns an object containing keys to update."

在这里的例子中,我们只传递一个参数,所以我们必须使用它,第一个参数是一个函数,returns 一个要更新的键对象。

如果我们再看一下使用 setState 的原始代码:

this.setState(prevState => counter(prevState, action));

如果我们用 es5 JavaScript 语法写这个可能会更容易阅读和理解:

this.setState(
  function cb(prevstate) {
    return counter(prevstate, action)
  })

所以在这种情况下 "prevState" 是匿名函数的参数。理论上,它可以被命名为任何东西,只要你在函数体内使用相同的名字来引用它,一切都会好起来的。然而,将它命名为 "prevState" 似乎是一个非常标准的事情(这是 React 文档使用的)。

如果我们将其视为纯粹的 JavaScript,则您传递给此函数的 prevState 应该是未定义的。

因此,多次触发 INCREMENT 操作应该会导致您的状态值始终为 1,因为计数器函数将始终使用默认值:

state = { value: 0 }

我认为调度函数应该是这样的:

dispatch(action) {
    this.setState(counter(this.state, action));
}

更新

This link 可能会更好地解释它,但实际上如果你使用一个函数作为 setState 的第一个参数,那么 这个函数将把当前状态作为它的参数,这就是 prevState 获取其值的方式。