从 Redux 容器分派一个动作而不扩展 React.Component

Posted

技术标签:

【中文标题】从 Redux 容器分派一个动作而不扩展 React.Component【英文标题】:Dispatching an action from a Redux container without extending React.Component 【发布时间】:2018-01-24 17:26:24 【问题描述】:

我的 React 和 Redux 应用程序中有一个容器组件:

import  connect  from 'react-redux'

import MyComponent from '../components/mycomponent'

const mapStateToProps = state => (
  myData: state.myData[state.activeDataId]
)

export default connect(mapStateToProps)(MyComponent)

如果state.myData[state.activeDataId] 不存在,那么我想向fetchMyDatafetchMyDataIfNeeded 发送一个操作。

请注意,目前,我的容器不包含任何 JSX,它只是将 props 转发到一个展示组件。我有 seen this being called a 'Pure Container' 虽然我不确定这是否是一个常用术语。

是否存在从纯容器调度操作的通用模式?我想没有:

期望演示组件通过向其传递 onLoad 事件来担心此逻辑 使容器成为 React.Component 并通过 componentDidMount 触发

从 mapStateToProps、mapDispatchToProps 或 mergeProps 调度操作是不是一个坏主意?

【问题讨论】:

在你的容器方法中调度动作是一个坏主意,这似乎是一种常见的做法,要么在你的子组件的 component* 函数中执行它,因为 connect HOC 通过dispatch 函数到 this.props 中的子组件。 【参考方案1】:

如其他地方所述,在容器中执行此操作是个坏主意。

不必担心容器中的这一点,有条件地在组件中获取数据是有意义的。我知道您提到不想扩展 react.component,但您绝对应该考虑将此组件设为一个类,以便在组件生命周期挂钩中获取数据。

正如另一个答案中详述的,connect 接受 mapDispatchToProps 的第二个参数。在那里传递 fetchData 调度程序(如何执行此操作的示例here。)

然后,在您的组件中,您可以检查 myData.如果它不存在,那么你通过发送

this.props.whatYouCalledDispatch()

【讨论】:

谢谢!您能否详细说明为什么在容器中调度操作是个坏主意?是否有任何特定的不良副作用? 纯容器实际上只是通过传递必要的状态和调度方法将指定的组件连接到商店。然后,组件(应该是一个类,而不是展示性的)将负责在需要时检索数据的业务逻辑。在容器中调用 dispatch 会很奇怪,因为它与组件的生命周期无关,因此可能会导致一些不需要的副作用(即没有在生命周期中正确/必要的时间进行调度)。如果有帮助,请投票或选择此答案。【参考方案2】:

是的,在容器中调度任何操作都是一个坏主意。 在您的情况下,最好的方法是:

将您的状态、动作创建者映射到组件道具 检查componentDidMount(或componentDidUpdate)和fetchDataYouNeed中的props,然后组件将被更新

你的容器应该是:

import  connect  from 'react-redux';
import fetchDataYouNeed from './actions
import MyComponent from '../components/mycomponent';

    const mapStateToProps = state => (
      myData: state.myData[state.activeDataId]
    );

    const mapDispatchToProps = (dispatch) => 
      return 
        fetchDataYouNeed: ()=>
          dispatch(fetchDataYouNeed());
        
      ;
    ;

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

你的组件

class YourComponent extends Component 

  componentDidMount()
    let myData, activeDataId = this.props;
    if(myData && !myData[activeDataId])
      this.props.fetchDataYouNeed();
    
  

  render()
    ....
  

在此处了解更多信息https://facebook.github.io/react/docs/react-component.html#componentdidmount

【讨论】:

谢谢!您能否详细说明为什么在容器中调度操作是个坏主意?是否有任何特定的不良副作用? 什么是容器?什么是组件? Container 只是智能组件(与 redux store 连接)。容器只需要做一件事:获取状态,将它们 + 动作创建者映射到组件。更改状态(调度操作)的最佳时间是当状态稳定(渲染组件)时。原因是我们不希望状态变化的混乱,这对管理和绩效都不利【参考方案3】:

这似乎有效,但我不确定它是否有任何意外影响:

import  connect  from 'react-redux'

import MyComponent from '../components/mycomponent'
import  fetchMyData  from '../actions/mydata'

const mapStateToProps = state => (
  dataId: state.activeDataId,
  myData: state.myData[state.activeDataId]
)

const mapDispatchToProps =  fetchMyData 

const mergeProps = (stateProps, dispatchProps) => 
  if (!stateProps.myData) 
    dispatchProps.fetchMyData(stateProps.dataId)
  
  return stateProps

export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(MyComponent)

另外,brianzinnsuggested 认为通过使用Redux Saga 来管理副作用,这个问题就变得多余了。

【讨论】:

以上是关于从 Redux 容器分派一个动作而不扩展 React.Component的主要内容,如果未能解决你的问题,请参考以下文章

使用 IIFE 从 Thunk 分派 Redux 操作

React Native Redux:动作分派,返回结果

从 redux-observable 的史诗有条件地调度额外的动作

如何一个接一个地调度两个异步 redux 动作?

如何在同一个史诗中调度多个动作

redux dispatch 多次触发