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

Posted

技术标签:

【中文标题】我不明白为啥带有\'connect()\'的组件在反应中是有状态的【英文标题】:I can't understand why components with 'connect()' are stateful in react我不明白为什么带有'connect()'的组件在反应中是有状态的 【发布时间】:2019-05-17 01:12:11 【问题描述】:

我的问题和标题一样。

假设我编写了以下代码。

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) 中,容器组件将数据作为状态处理,而表现属性作为道具处理。它不是一个将数据作为道具处理的表示组件吗?我坚持认为正确的容器应该如下所示。

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”

【问题讨论】:

“状态”不是特定于反应的术语,它是计算机编程的通用术语。这是一个通用术语,表示系统的记忆状态。 en.wikipedia.org/wiki/State_(computer_science)。 Redux reducer 状态和组件状态是不同的东西。 【参考方案1】:

首先,这些指南不是圣经的一部分 您应该为您和您的团队编写易于推理的代码。

我认为您遗漏了一些东西,redux Container 与 react Container 不同。 我的意思是,connect 会为你创建容器,这并不意味着被包装的组件 一个容器。

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

另一件通常会让人们失望的是mapStateToProps的函数和参数的名称。 我更喜欢 mapStoreToProps 这个名字,就像

redux 存储映射到组件的道具。

当我们在react 的上下文中时,名称state 可能会令人困惑。

编辑 作为您评论的后续行动:

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

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

connect 是一个高阶组件,它为我们创建了 Container Component,它具有所有订阅逻辑 + 将部分 store 和 action-creators 作为 props 传递给其子级的函数(mapStateToProps & mapDispatchToProps) .

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

至于其他cmets之类的

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

正如我上面提到的,这是部分正确的。它不仅仅是将属性注入到我们的组件中,它订阅存储,从Provider(通过context)获取它,并且它在做所有这些时都考虑到了优化,所以我们不必自己做.

我不确定 mapStateToProps 会如何迷惑别人。我们说的是状态管理库

我看到一些开发人员误解了这一点,因为 react 有一个 stateredux 有一个 store(至少在大多数教程和文档中都是这样称呼的)。 这可能会让一些不熟悉reactredux 的人感到困惑。

编辑 2

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

我的意思是您编写的包装组件不一定是容器。 你可以连接一个“Presentation”组件:

const Link = ( active, children, onClick ) => 
  if (active) 
    return <span>children</span>
  

  return (
    <a
      href=""
      onClick=e => 
        e.preventDefault()
        onClick()
      
    >
      children
    </a>
  )


// ...
export default connect(mapState, mapDispatch)(Link)

【讨论】:

感谢您的回答。但我不明白这部分:'我认为你遗漏了一些东西,redux Container 与 react Container 不同。我的意思是,connect 会为你创建容器,这并不意味着被包装的组件就是一个容器。是的,我完全不知道这两个实际上是不同的。你能告诉我更多细节吗? 我不知道mapStateToProps 怎么能迷惑别人。我们正在谈论一个状态管理库。 react-reduxconnect HoC 只是将您可以请求的属性注入到您的组件中。它返回一个包裹在你的组件周围的新组件,以便它可以在你对 redux 存储感兴趣的状态被修改时更新你的组件。 我添加了更多细节来回答一些 cmets @Rhee 我已经回答了你最新的评论(编辑 2 部分)希望能澄清它:)【参考方案2】:

mapStateToProps 将在存储数据更改时调用。它将返回的对象作为组件的新道具传递。这不会影响组件的状态。如果您想在组件获得新的 props 后设置新状态,则需要使用另一种生命周期方法: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”

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

【讨论】:

【参考方案3】:

高级目的是将 Redux 的状态管理无缝集成到 React 应用程序中。 Redux 围绕所有 state 存在的 store 展开。没有办法直接修改 store,除非通过 reducer 从动作创建者那里接收动作,为此我们需要从动作创建者那里分派一个动作。

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

这是 Redux 的强大之处,也是我们使用它的原因。

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

然后,您可以从 react-redux 导入 connect() 函数,将其传递给 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>;
  

【讨论】:

以上是关于我不明白为啥带有'connect()'的组件在反应中是有状态的的主要内容,如果未能解决你的问题,请参考以下文章

我不明白为啥 Angular 组件类 add 实现 onInit 接口

在制作反应组件 es6 语法时,为啥用道具超级初始化? [复制]

为啥 withRouter 与 connect() 一起使用会破坏我的反应应用程序?

React父组件中的onClick事件不起作用

反应+还原。 Connect 不更新组件的状态

为啥这种带有动态输入值的表单验证不起作用?