How to dispatch Redux action from stateless component when route is loaded? How to dispatch Redux action from stateless component when route is loaded? reactjs reactjs

How to dispatch Redux action from stateless component when route is loaded?


I don't know why you absolutly want a stateless component, while a stateful component with componentDidMount would do the job in a simple way.

Dispatching actions in mapDispatchToProps is very dangerous and may lead to dispatching not only on mount but whenever ownProps or store props changes. Side effects are not expected to be done in this method that should remains pure.

One easy way to keep your component stateless is to wrap it into an HOC (Higher-Order Component) that you could easily create:

MyStatelessComponent = withLifecycleDispatch(dispatch => ({   componentDidMount: function() { dispatch({ type: myActionTypes.DATA_GET_REQUEST })};}))(MyStatelessComponent)

Note that if you use Redux connect after this HOC, you can easily access dispatch from props directly as if you don't use mapDispatchToProps, dispatch is injected.

You can then do something very simple like:

let MyStatelessComponent = ...MyStatelessComponent = withLifecycle({   componentDidMount: () => this.props.dispatch({ type: myActionTypes.DATA_GET_REQUEST });})(MyStatelessComponent)export default connect(state => ({   date: state.myReducer.data}))(MyStatelessComponent);

HOC definition:

import { createClass } from 'react';const withLifeCycle = (spec) => (BaseComponent) => {  return createClass({    ...spec,    render() {      return BaseComponent();    }  })}

Here is a simple implementation of what you could do:

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)

If you use connect around Hello component, they you can inject dispatch as props and use it instead of an alert message.

JsFiddle


I think I found the cleanest solution without having to use stateful components:

const onEnterAction = (store, dispatchAction) => {    return (nextState, replace) => {        store.dispatch(dispatchAction());    };};const myDataFetchAction = () => ({ type: DATA_GET_REQUEST });export const Routes = (store) => (    <Route path='/' component={MyStatelessComponent} onEnter={onEnterAction(store, myDataFetchAction)}/>);

The solution passes the store to a higher order function that is passed to the onEnter lifecycycle method.Found the solution from https://github.com/reactjs/react-router-redux/issues/319


Now days you can use the useEffect hook as such:

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

This is the equivalent for the componentDidMount/componentWillMount life cycle methods of functional/stateless components.

For further reading on hooks: https://reactjs.org/docs/hooks-intro.html