Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dispatch an action on componentDidMount (react/redux)

Tags:

I am relativity new to react/redux. There for I want to ask a (perhaps a philosophic) question.

Is it ok to to dispatch an action (e.g. to trigger an api-call) on componentDidMount of a react component?

If not, why and where should I dispatch the action?

If yes, then no further questions? :)

like image 201
dritan Avatar asked May 03 '17 15:05

dritan


People also ask

Can we call componentDidMount?

componentDidMount() method As the name suggests, after all the elements of the page is rendered correctly, this method is called. After the markup is set on the page, this technique called by React itself to either fetch the data from An External API or perform some unique operations which need the JSX elements.

Can I dispatch action in mapStateToProps?

It could be related to event, dispatch is just a function and the only way to change your application state. mapStateToProps is one way to expose dispatch function of your store to React Component.

How can I call Redux action from functional component?

There are two ways to dispatch actions from functional components: Using mapDispatachToProps function with connect higher order component, same as in class based components. Using useDispatch hook provided by react-redux . If you want to use this hook, then you need to import it from the react-redux package.


2 Answers

Yes, dispatching an action on componentDidMount() is OK, and even the recommended thing to do since it will not slow down the initial UI render.

Since the function runs after the component has initially rendered, keep in mind that you may have sometime between the moment the component is rendered, and the moment you receive the data from the api call.

like image 102
Sammy I. Avatar answered Sep 19 '22 19:09

Sammy I.


Yes, you should definately use the componentDidMount hook.

A typical use case might be :

  • Component appears on screen, eg a table
  • Request to the server is triggered to get data
  • A spinner/loader is shown to cover the component
  • data comes back
  • spinner is removed and data is shown in the table.

I know its a bit long, but I was working myself on this type of problem for a while, so I thought I would share the following pattern ;)

When the component mounts then a fetch data action is triggered. An 'isFetching' value in the application state determines whether the spinner is shown or not (I think i used 'advanced-loader' or some such library)

export default class MyComponent extends React.Component {

  componentDidMount() {
    AppDispatcher.dispatch({
      type: ActionTypes.FETCH_DATA,
    });
  }

  render() {
    let isFetching = this.props.my.application.path.isFetching;
    return (
      <Loader show={isFetching} message={'loading'}>
        <div>
          My Component
        </div>
      </Loader>
    );
  }
}

Then in the store the FETCH_DATA triggers a request :

class AppStore extends ReduceStore {

  //......

  reduce(state, action) {

    let imState = Immutable.fromJS(state);

    switch (action.type) {

      //......

      case ActionTypes.FETCH_DATA:
        doGetRequest('/url_to_service');
        break;

      //......
    }
    return imState.toJS();
  }
}

The request would look something like this :

function doGetRequest(endpoint, params = {}) {

  //request is some kind of AJAX library. In my case 'superagent'
  request.get(endpoint)
    .set('Accept','application/json')
    .query(params)
    .end(
      (err, res) => {
        if (res && res.ok) {
          receiveData(endpoint, "SUCCESS", res);
        } else {
          receiveData(endpoint, "FAIL");
    }});
}

Upon completion it would then dispatch another action.

function receiveData(endpoint, state, responseData) {
  AppDispatcher.dispatch(
    {
      type: ActionTypes.SERVER_RESPONSE,
      endpoint: endpoint,
      state: state,
      payload: responseData
    }
  );
}

Going back to the store, the second action is caught and the isFetching flag is set to false, then the application data is handled.

  reduce(state, action) {

    let imState = Immutable.fromJS(state);

    switch (action.type) {

      //......


      case ActionTypes.SERVER_RESPONSE: {

        imState = imState.setIn(['my','application','path', 'isFetching'], false)

        if (action.state == "SUCCESS") {
            //do something with the action.response data (via state update)
        }else if (action.state == "FAIL") {
            //maybe show an error message (via state update)
        }
        break;
      }
    }
    return imState.toJS();
  }
}

.... so this typical use case uses two 'actions', the first action being triggered from the componentDidMount method, and the second action is triggered after the request finishes.

Hope this pattern helps :)

like image 29
Oliver Watkins Avatar answered Sep 19 '22 19:09

Oliver Watkins