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