如何在加载路由时从无状态组件调度Redux操作?

Kit*_*ori 28 reactjs redux-saga react-redux react-router-redux

目标:在加载反应路由器路由时,调度Redux操作,请求异步Saga工作程序获取该路由的基础无状态组件的数据.

问题:无状态组件仅仅是函数,没有生命周期方法,例如componentDidMount,所以我不能(?)从函数内部调度Redux操作.

我的问题部分与将有状态React组件转换为无状态功能组件有关:如何实现"componentDidMount"类功能?,但我的目标是仅发送一个Redux动作,要求将数据异步填充到商店(我使用Saga,但我认为这与问题无关,因为我的目标是仅发送一个普通的Redux动作),之后由于数据支柱的改变,无状态组件将重新渲染.

我正在考虑两种方法:使用react-router的一些功能,或Redux的connect方法.是否有一种所谓的"反应方式"来实现我的目标?

编辑:到目前为止我唯一提出的解决方案是在mapDispatchToProps中调度动作,这样:

const mapStateToProps = (state, ownProps) => ({
    data: state.myReducer.data // data rendered by the stateless component
});

const mapDispatchToProps = (dispatch) => {
    // catched by a Saga watcher, and further delivered to a Saga worker that asynchronically fetches data to the store
    dispatch({ type: myActionTypes.DATA_GET_REQUEST });
    return {};
};

export default connect(mapStateToProps, mapDispatchToProps)(MyStatelessComponent);
Run Code Online (Sandbox Code Playgroud)

然而,这似乎有点脏,而不是正确的方式.

Seb*_*ber 11

我不知道为什么你绝对想要一个无状态组件,而一个有componentDidMount的有状态组件会以一种简单的方式完成工作.

调度操作mapDispatchToProps非常危险,并且可能导致不仅在mount时调度,而且每当ownProps或store props更改时都会调度.预计这种方法不会产生副作用,应保持纯净.

保持组件无状态的一种简单方法是将其包装到您可以轻松创建的HOC(高阶组件)中:

MyStatelessComponent = withLifecycleDispatch(dispatch => ({
   componentDidMount: function() { dispatch({ type: myActionTypes.DATA_GET_REQUEST })};
}))(MyStatelessComponent)
Run Code Online (Sandbox Code Playgroud)

请注意,如果您在此HOC之后使用Redux连接,则可以直接从props直接访问调度,就像您不使用一样mapDispatchToProps,注入调度.

然后你可以做一些非常简单的事情:

let MyStatelessComponent = ...

MyStatelessComponent = withLifecycle({
   componentDidMount: () => this.props.dispatch({ type: myActionTypes.DATA_GET_REQUEST });
})(MyStatelessComponent)

export default connect(state => ({
   date: state.myReducer.data
}))(MyStatelessComponent);
Run Code Online (Sandbox Code Playgroud)

HOC定义:

import { createClass } from 'react';

const withLifeCycle = (spec) => (BaseComponent) => {
  return createClass({
    ...spec,
    render() {
      return BaseComponent();
    }
  })
}
Run Code Online (Sandbox Code Playgroud)

以下是您可以执行的操作的简单实现:

const onMount = (onMountFn) => (Component) => React.createClass({
   componentDidMount() {
     onMountFn(this.props);
   },
   render() { 
      return <Component {...this.props} />
   }  
});

let Hello = (props) => (
   <div>Hello {props.name}</div>
)

Hello = onMount((mountProps) => {
   alert("mounting, and props are accessible: name=" + mountProps.name)
})(Hello)
Run Code Online (Sandbox Code Playgroud)

如果你使用connectHello组件,你可以将dispatch注入为道具并使用它而不是警告消息.

的jsfiddle


Ita*_*ton 6

现在你可以useEffect这样使用钩子:

import React, { useEffect } from 'react';
const MyStatelessComponent: React.FC = (props) => {
   useEffect(() => {
      props.dispatchSomeAction();
   });
   return ...
}
Run Code Online (Sandbox Code Playgroud)

componentDidMount这与功能/无状态组件的/生命周期方法等效 componentWillMount

有关钩子的进一步阅读:https ://reactjs.org/docs/hooks-intro.html


Har*_*uja 1

如果您希望它完全无状态,您可以在使用 onEnter 事件输入路线时调度一个事件。

<Route to='/app' Component={App} onEnter={dispatchAction} />
Run Code Online (Sandbox Code Playgroud)

现在,您可以在此处编写函数,只要您在此文件中导入调度或以某种方式将其作为参数传递即可。

function dispatchAction(nexState,replace){
   //dispatch 
}
Run Code Online (Sandbox Code Playgroud)

但我觉得这个解决方案更肮脏。

我真正有效的另一个解决方案是使用容器并在其中调用 componentDidMount 。

import React,{Component,PropTypes} from 'react'
import {connect} from 'react-redux'

const propTypes = {
 //
}

function mapStateToProps(state){
//
}

class ComponentContainer extends Component {

  componentDidMount(){
    //dispatch action
  }
  render(){
    return(
      <Component {...this.props}/> //your dumb/stateless component . Pass data as props
    )
  }
} 

export default connect(mapStateToProps)(ComponentContainer)
Run Code Online (Sandbox Code Playgroud)