dispatch an action on componentDidMount (react/redux)

前端 未结 4 731
有刺的猬
有刺的猬 2021-02-18 16:41

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

4条回答
  •  暗喜
    暗喜 (楼主)
    2021-02-18 17:04

    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 (
          
            
    My Component
    ); } }

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

提交回复
热议问题