React-Redux 中的 actionCreator、props 和组件是如何连接的?

IT技术 reactjs redux react-redux
2021-05-12 11:24:53

我有这个代码:

import React, { Component } from 'react';
import { connect } from 'react-redux'; //this is a single connect property
import { selectBook } from '../actions/index';
import { bindActionCreators } from 'redux';

class BookList extends Component {
  renderList() {
    return this.props.books.map(book => {
      return (
        <li key={book.title} className="list-group-item"> {book.title} </li>
      );
    });
  }

  render() {
    return (
      <ul className="list-group col-sm-4">
        {this.renderList()}
      </ul>
    )
  }
}

function mapStateToProps(state) {
  return {
    books: state.books
  }
}

function mapDispatchToProps(dispatch) {
  // Whenver selectBook is called, the result should be passed to all of the reducers.
  // selectBook value is an actionCreator, a function.
  return bindActionCreators({ selectBook: selectBook }, dispatch)
}

export default connect(mapStateToProps, mapDispatchToProps)(BookList)

export function selectBook(book) {
  console.log("A book has been seelcted:", book.title)
}

我不明白的部分是这样的:

connect(mapStateToProps, mapDispatchToProps)(BookList)

到底是怎么回事?这部分是否负责使组件可以使用状态和分派方法BookList

这个函数是做什么的:

function mapDispatchToProps(dispatch) {
  // Whenver selectBook is called, the result should be passed to all of the reducers.
  // selectBook value is an actionCreator, a function.
  return bindActionCreators({ selectBook: selectBook }, dispatch)
}

这些是内置的 redux 函数吗?他们返回什么?到底是怎么回事?什么是dispatch

selectBook右边的值是一个函数吧?所以我猜它被调用了,返回值将通过 dispatch 方法流经 reducer?但那又在bindActionCreators做什么呢?

props 如何在组件内部可用BookList

1个回答

你有太多的问题,我们如何努力解释这里发生的事情可能会让你更加困惑。我强烈建议您观看 Redux 创建者的这两个视频:

Redux惯用的 Redux入门

这些视频解释了什么是 Redux,它的各个部分是如何组合在一起的。因此,在学习任何其他教程之前,首先要掌握 Redux 本身。

此外,Redux 的官方文档也很棒,如果您将其与视频一起学习,对您的学习会很有帮助。

但是,无论如何,让我回答你的问题。

第一个问题

我不明白的部分是这样的:

connect(mapStateToProps, mapDispatchToProps)(BookList)

到底是怎么回事?这部分是否负责使组件 BookList 可以使用状态和调度方法?

回答

connect这里是由react-redux提供的,而不是redux它本身。它是一个辅助高阶函数,用于向组件打开状态和动作创建器。所以,你猜对了。这就是人们通常将他们的组件连接到商店以获取状态和分派(以使用动作创建者)的方式。

第二个问题

function mapDispatchToProps(dispatch) {
  // Whenver selectBook is called, the result should be passed to all of the reducers.
  // selectBook value is an actionCreator, a function.
  return bindActionCreators({ selectBook: selectBook }, dispatch)
}

这些是内置的 redux 函数吗?他们返回什么?到底是怎么回事?什么是派遣?

右边的值 selectBook 是一个函数吧?所以我猜它被调用了,返回值将通过 dispatch 方法流经 reducer?但是 bindActionCreators 在做什么呢?

如何在组件 BookList 中提供props?

回答

不,它们不是像我在第一个答案中解释的那样内置于 Redux 函数中。mapStateToProps将您的状态打开到您的组件并将其作为props提供。所以,如果你打开任何状态给你的组件,connect并且mapStateToProps你得到这个状态作为props。在您的示例中,您books从全局状态获取状态并将其打开books到您的组件。然后这个组件将其作为this.props.books.

mapDispatchToProps将您的动作创建者函数作为props打开给您的组件。有几种使用它的方法,bindActionCreators是其中之一,但实际上您在这里不需要它。如果您在将动作创建者分派或传递给不知道 Redux 的子组件时需要它,则可以获取状态。所以,bindActionCreators不是一个好的开始理解mapDispatchToProps

基本上是这样的:

const mapDispatchToProps = dispatch => ({
  someFunction: () => dispatch(someFunction())
})

在这里,您someFunction()以 name 的形式向您的组件打开您的动作创建者someFunction你可以使用不同的名字,或者你可以在这里做其他员工,然后dispatch根据这个你的动作创建者。但是在这个例子中,你没有做任何额外的事情,只是调度动作创建者。所以,有一个简写:

const mapDispatchToProps = {
    someFunction,
}

是的,对于这种情况,这会做同样的事情。甚至,还有一个更短的:

connect(mapStateToProps, {someFunction})(Component)

不使用 amapDispatchToProps你可以像这样使用你的动作创建者,然后在你的组件中作为props。

此外(是的,还有更多 :))在连接中不使用任何函数参数的事件,我们可以使用动作创建者。

connect()(Component)
connect(mapStateToProps)(Component)

如果我们mapDispatchToProps像上面的方法之一一样跳过dispatch则会自动传递给组件props。然后,我们可以像使用任何其他props一样使用它来调度我们的动作创建者:

this.props.dispatch(someFunction())

对于你的例子,它是这样的(我知道这个应用程序,所以我在这里使用真实的动作创建者示例)。

你可以这样写mapDispatchToProps

const mapDispatchToProps = dispatch => ( {
  selectBook: book => dispatch( selectBook( book ) ),
} );

在这里你在你的组件中使用selectBookasthis.props.selectBook并调度一个动作。你实际上看到你的props触发了一个函数,它在这里调度你的真实动作创建者。请记住,动作创建者返回对象,这些对象需要被分派才能通过 reducer。因此,您正在调度您的动作创建者(由selectBook.

现在,在bindActionCreators不使用其真正优势的情况下,您可以将其写为:

const mapDispatchToProps = dispatch => (
    bindActionCreators( { selectBook: selectBook }, dispatch )
);

或者使用 ES6 的一些具有相同名称的对象键的简写:

const mapDispatchToProps = dispatch => (
    bindActionCreators( { selectBook }, dispatch )
);

这比第一个略短。你不需要指向一个函数并调度它。您将动作创建者交给了bindActionCreators它,它会为您完成工作。

现在,由于您只是在调度,因此较短:

const mapDispatchToProps = {
  selectBook,
};

即使没有mapDispatchToProps

connect( mapStateToProps, { selectBook } )( BookList )

因此,Provider,connect正在提供,react-redux以使我们的生活更轻松。mapStateToPropsmapDispatchToPropsconnect等待的功能名称并不重要,我们可以为它们使用任何名称,但这些是每个人都使用的事实上的名称。顺序很重要,如果我们想跳过,mapStateToProps我们必须null在它的位置使用,例如:

connect( null, mapDispatchToProps )( Component )

如果没有connect其实我们可以使用store和它包含什么getStatedispatchsubscribe用两种方法的任何组件:

  • 不要一直使用as propsreact-redux并将其传递store给您要使用的每个组件。然后通过this.props.store.
  • 使用react-redux's Provider,然后使用contextfor 组件来获取store.

可以想象,将 store 一直传递到组件是一场噩梦。

首先使用storewith,context您需要指定contextTypes组件的 :

BookList.contextTypes = {
  store: React.PropTypes.object.isRequired
};

这样做之后,您可以从中获取 storethis.context.store并使用它getState来获取状态或dispatch调度您的动作创建者。

如果我们不使用,我们的组件将会如何connect

import React, { Component } from "react";
import { selectBook } from "../actions/index";

class BookList extends Component {
  renderList() {
    return this.context.store.getState().books.map( book =>
      ( <li
        key={book.title}
        onClick={() => this.context.store.dispatch( selectBook( book ))}
      >
        {book.title}
      </li> ) );
  }

  render() {
    return (
      <ul>
        {this.renderList()}
      </ul>
    );
  }
}

BookList.contextTypes = {
  store: React.PropTypes.object.isRequired,
};

export default BookList;

这里我们使用:this.context.store.getState().books代替this.props.booksthis.context.store.dispatch( selectBook( book ))代替this.props.selectBook( book )如您所见,我们可以通过这种方式到达状态并调度我们的动作创建者。但是凭借connect其灵活性,我们以一种漂亮而干净的方式打开我们的状态和动作创建器。