dispatch an action on componentDidMount (react/red

2020-06-30 07:12发布

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? :)

4条回答
唯我独甜
2楼-- · 2020-06-30 07:32

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.

查看更多
Luminary・发光体
3楼-- · 2020-06-30 07:42

According to the official React documentation, componentDidMount is exactly the right place to do so:

componentDidMount() is invoked immediately after a component is mounted. Initialization that requires DOM nodes should go here. If you need to load data from a remote endpoint, this is a good place to instantiate the network request.

Official React Documentation for componentDidMount()

查看更多
冷血范
4楼-- · 2020-06-30 07:51

When using routes another recommended way to dispatch an action would be the routes-method "onEnter". This is in order to make the component not dependent from actions (or api-calls).

I personally think both methods (componentDidMount vs. onEnter) are ok. It is left to the programmer to choose which solution is best for his application.

查看更多
Evening l夕情丶
5楼-- · 2020-06-30 07:54

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 :)

查看更多
登录 后发表回答