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? :)
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.
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.
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.
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.
Yes, you should definately use the componentDidMount hook.
A typical use case might be :
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 :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With