我不明白为什么带有'connect()'的组件在反应中是有状态的

时间:2018-12-16 12:37:41

标签: javascript reactjs redux react-redux

我的问题和标题一样。

假设我写了以下代码。

class TODOList extends Component {  
  render() {
    const {todos, onClick} = this.props;
    return (
      <ul>
            {todos.map(todo =>
                <Todo 
                    key={todo.id}
                    onClick={onClick}
                    {...todo}
                />
             )}
      </ul>
    );
  }
}


const mapStateToProps = (state) => {  
  return {
    todos: state.todos
  }
}


const mapDispatchToProps = (dispatch) => {  
    return {
        onClick(data){
          dispatch(complete(data)) 
        }
    }
}


export default connect(mapStateToProps,mapDispatchToProps)(TODOList); 

现在,在最后一行之后,此代码将导出状态为道具的TODOList组件。并不是说它包含状态,而是只是接收到状态,并将其作为“属性”,就像方法名“ mapStateToProps”所说明的那样。

在Dan Abramov撰写的中篇文章(https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0)中,容器组件将数据作为状态来处理,而presentational属性作为道具来处理。它不是将数据作为道具处理的表示性组件吗?我坚持认为正确的容器应为以下容器。

class CommentList extends React.Component {
  this.state = { comments: [] };

  componentDidMount() {
    fetchSomeComments(comments =>
      this.setState({ comments: comments }));
  }
  render() {
    return (
      <ul>
        {this.state.comments.map(c => (
          <li>{c.body}—{c.author}</li>
        ))}
      </ul>
    );
  }
}

当我尝试使“有状态”(不按属性处理数据)容器组件时,我不确定为什么react-redux将API命名为“ mapStateToProps”

3 个答案:

答案 0 :(得分:10)

首先,这些指南不是圣经的一部分
您应该编写易于理解的 YOU和您的TEAM 代码。

我认为您缺少了一些东西,redux容器与react容器不同。
我的意思是,connect将为您创建容器,这并不意味着包装的组件一个容器。

基本上,您可以从同一文件中导出两个版本,即容器(连接的版本)和演示文稿版本(不连接的版本)。

通常会使人失望的另一件事是mapStateToProps的函数名称和参数。
我更喜欢mapStoreToProps的名称,如

  

redux存储区映射到组件的props。

state的上下文中,名称react可能会造成混淆。

修改
作为您评论的后续内容:

  

我完全不知道这两个实际上是不同的。你能告诉我更多细节吗?

connect为您创建“容器”的方式有所不同。

connect是一个高级组件,它为我们创建了Container Component,具有所有订阅逻辑+函数,以将部分商店和动作创建者作为道具({{1} }和mapStateToProps

“普通”容器通常是指您用手工编写的组件,它通常不处理外观,而是处理应用程序的某些逻辑。

关于其他评论,例如

  

react-redux的connect HoC只是将您可以请求的属性注入到组件中。它返回一个包裹在您的组件周围的新组件,以便在您对redux存储感兴趣的状态被修改时可以更新您的组件

如上所述,这部分是正确的。这不仅是将属性注入到我们的组件中,它还可以订阅商店,从mapDispatchToProps(通过Provider抓取),并且在进行所有这些操作时都考虑了优化,因此我们不必自己做。

  

我不确定mapStateToProps如何使某人困惑。我们正在谈论一个状态管理库

我看到一些开发人员误解了这一点,因为context有一个react,而state有一个redux(至少在大多数情况下就是这样教程和文档)。
这可能会使一些刚接触storereact的人感到困惑。

编辑2

  

由于这句话“这并不意味着包装的组件是容器”,这有点令人困惑。为什么包装的组件不是容器?不是通过connect创建的组件也是容器吗?

我的意思是您编写的包装组件不必是一个容器。
您可以连接“演示文稿”组件:

redux

答案 1 :(得分:2)

存储数据更改时,将调用

mapStateToProps。它将把返回的对象作为组件的新道具传递。这不会影响组件的状态。如果您想在组件获得新道具后设置新状态,则需要使用另一种生命周期方法:static getDerivedStateFromProps(在早期版本的react componentWillRecieveProps中)。 static getDerivedStateFromProps返回的对象将是您的新状态。

https://reactjs.org/docs/state-and-lifecycle.html#adding-lifecycle-methods-to-a-class

connect()会将您的组件连接到redux存储。没有连接功能(当然),您的mapStateToProps将无法工作。

  

我不确定为什么react-redux将API命名为“ mapStateToProps”

我们正在谈论商店的状态:)

答案 2 :(得分:0)

高级目的是将Redux的状态管理无缝集成到React应用程序中。 Redux围绕着所有状态都存在的商店。除了通过还原者(它从动作创建者那里接收动作)接收到的现金以外,没有其他方法可以直接修改商店。为此,我们需要从动作创建者中分发动作。

connect()函数通过获取Redux存储中的状态并将其映射到prop中,将我们的组件直接连接到Redux存储。

这是Redux的强大功能以及我们使用它的原因。

可以说您正在构建一个名为LaundryList的组件,并且希望它呈现一个洗衣清单。在将Provider连接到“父”组件中之后,我将其用引号引起来,因为从技术上讲,Provider是一个组件,因此它成为父组件。

然后,您可以从connect()导入react-redux函数,并将其传递给mapStateToProps,以便从Redux商店中获取该洗衣清单到您的LaundryList组件中。

现在,您在LaundryList组件中有了亚麻布清单,您可以开始着重于从其中构建元素清单,如下所示:

class LaundryList extends Component {
  render() {
    console.log(this.props.linens);
    return <div>LaundryList</div>;
  }
}

其中包含亚麻布对象列表,对于其中的每个亚麻布列表,我们将返回一些jsx来表示我的亚麻布列表。

回到洗衣清单组件内部,我将在洗衣清单组件内部添加一个名为render list的帮助方法,如下所示:

class LaundryList extends Component {
  renderList() {

  }

  render() {
    return <div>LaundryList</div>;
  }
}

因此,此辅助方法的目的是获取亚麻布的列表,在它们上进行映射,然后像这样返回大的jsx斑点:

class LaundryList extends Component {
  renderList() {
    return this.props.linens.map((linen) => {
       return (

       );
    });
  }

  render() {
    return <div>LaundryList</div>;
  }
}