Or in other words, how do i know when a action that's dispatched is complete?
I have a webapp where I'd update the redux store through dispatches on user input. If i push the redux store's state to the server right after dispatching, the server does not have the most updated info. I need to wait for the action to complete prior to pushing to server, hence the question.
EDIT
Based on markerikson's answer I solved it. I thought dispatch was called asynchronously but the execution of the group of dispatched actions happened synchronously. That's wrong and mark's right. My issue was the the update server call was made in a component and it pushes to server a prop that needed to be updated by redux-store. That updating of the prop didn't happen fast enough.
A little late to the question, but for the people who got here based on the question title - take a look into:
store.subscribe()
store.getState()
where 'store' is a reference to your redux store.
store.subscribe(() => {
const newState = store.getState();
// check out your updated state
});
the code above would run anytime there is an update to the redux state
Dispatching is entirely synchronous, unless altered by a middleware. So, as soon as the call to dispatch() returns, the store state has been updated and all subscribers have been notified.
If you need to wait for some async behavior to complete, you can write a thunk that returns a promise, and chain off that when you dispatch:
function someThunkReturningAPromise() {
return (dispatch) => {
const promise = myAjaxLib.fetchData().then(response => {
dispatch(loadData(response.data));
});
return promise;
}
}
dispatch(someThunkReturningAPromise()).then( () => { });
Related
I am trying to get my head around a scenario where I am dispatching a synchronous redux action (using createAction of typesafe-actions) and soon after that making a network call that relies on updated props from the store.
Scenario:
Inside clearFilters handler function (handler function invoked on click of clear filters button), I am dispatching a synchronous action and then making a network call as below:
clearFilters = (): void => {
this.props.resetFilters(); //action dispatched
this.refreshData; //network call
};
Inside the refreshData function, my component expects updated filter props and based on it, it creates a searchCondition to be passed to the list api call as payload.
refreshData = (): void => {
const { listData, filters } = this.props; //get the filters prop
//Expected filters to be updated from the store post dispatch of action
const SearchCondition: SearchCondition = createSearchConditions(filters);
listData({
SearchCondition,
MaxResults: this.maxRecordsCount,
SortFields: this.getSortFields(),
}),
);
};
My component is subscribed to the filters prop using mapStateToProps:
const mapStateToProps = (state: RootState) => ({
filters: state.common.filter.filters,
});
Given that is the state of the problem I am facing, I tried to debug what happens by placing debug points in the code:
When the action is dispatched (inside clearFilters function)
Inside the reducer, where updated state is returned.
When the network call is invoked (inside clearFilters function)
In the refreshData call.
After reducer returns updated state, as per the debugging knowledge, store did not send the updated props right away. Rather, the control goes back to the next line i.e. this.refreshData() which make network call with old filters data. Only after the clearFilters function call finishes, in my componentDidUpdate, i can see that props update happen.
Does that signifies redux state change back to the store and eventually subscribed prop updates happen in an ASYNC way? If so, how does it happen? Does store sending the updated props executes in the main thread?
Any pointers/documentation would be really helpful.
The dispatch is synchronous, and the queueing of the React updates is synchronous. However, React will not re-render that component until after this whole event processing is completed, and this.props will not be updated until after that render happens. So, no, you cannot access this.props right after dispatching an action and expect that it has been updated. That will never be true.
I would suggest reading these posts that go into extensive detail on both React and React-Redux:
A (Mostly) Complete Guide to React Rendering Behavior
The History and Implementation of React-Redux
My reducer returns state in a async way, since it will interact with another component, how to make the component re-render after reducer update state in the .then?
switch (action.type) {
case RELEASE_PAYMENT:
(new PaypalContract())
.releasePayment(action.id)
.then(() => (new PaypalContract()).getState(action.id))
.then(function(e) {
console.log("status in orderReducer:",status[e])
return{
...state,
orderStatus: status[e]
}
})
return state
You can't return the state twice from the reducer function and you can't return the updated state from the reducer function in an asynchronous way.
Returning something from the callback function of the .then() method doesn't makes it a return value of the outer function, i.e. reducer function in your case.
Reducer functions are synchronous, they take in a action and based on the action return the updated state. All of this is done synchronously.
What you are doing in your reducer function won't work as you expect it to and the return statement at the of your reducer function will always execute before asynchronous code completes. This means that your reducer function always returns the same state which means that your redux store never updates.
Solution
What you need is a way to dispatch an action that triggers the data fetching and once the data is available, another action should be dispatched that is received by the reducer function. This new action should contain the data that is fetched asynchronously, as a payload and the reducer function will just update the state appropriately using the payload associated with the action.
Following are the couple of options that allow you to do just that:
redux thunk
Redux Saga
Using the first option is easier so i would recommend to start with that but you could also explore the second option which also help with advanced use cases.
Here are couple of resources to get you started with each of the options mentioned above:
Redux Thunk Explained with Examples
Redux Saga Example
You need to pass the data to the reducer after you get the response from the API. It will be simpler to control the flow of data. You can make use of async/await in this.
async function_name() {
const res = await API_CALL_HERE
res.then( data => INVOKE_YOUR_DISPATCH_HERE(data))
.catch(err => console.log('error'));
}
In reducer
case RELEASE_PAYMENT:
return {...state, orderStauts:data[e]
How do I execute custom callback that is passed into an action through react comp, immediately after redux store update.
The idea is say, I trigger an action from react, which will make network request via thunk and dispatches the action with data. This will lead to reducer updating the store. Now, immediately after this I want to redirect to a different page (history.push()) which is a callback.
Using saga middleware it is much easier, but how to implement similar functly using thunk.
You can pass your callback defined in your component the redirect to different page to the thunk and call that after store update is complete. Like this:
function someThunkAction(callback) {
return (dispatch, getState) => {
// Update store logic...
// After update
callback();
};
}
My questions is a conceptual one and based on the issue outlined in this post: React Redux capture updated store state after updating database. I don't think any code is needed to understand or be able to answer it. But if not it is at the link above.
I think I might have missed a small detail about the react/redux state update process following an action that changes the back-end data that a state variable reflects. My question is: When I dispatch a save action, should I then also be dispatching a request to update any state that depends on that underlying data?
So for example, right now the way I'm thinking about it and implementing my code is as follows:
app starts and ParentComponent loads and dispatches GET_DATA on componentDidMount which initializes state variable data which is reflected on ParentComponent in a table
when a link is clicked on ParentComponent, ParentComponent renders ChildComponent which is a react-modal popup that displays elements of data so it can be updated
there is and Save and Close button on ChildComponent; when you click the button, SAVE_DATA is dispatched and the changes to data that are made on ChildComponent get saved to the database
THIS is where my question arises... at this point should I also be calling GET_DATA to dispatch the process of "refreshing" data in my state? Would this be the right way to handle saving data to a database when using redux so that all components that rely on data get updated?
Note: What I'm currently doing is that after step 3, I am simply triggering a refresh function in ParentComponent so that it rerenders and hence reflects data in state. The epiphany I just had is that there is no way for data in state to reflect the new saved data because GET_DATA has not been dispatched after saving and rerendering the component does not trigger GET_DATA.
Are my assumptions correct? Should I be calling GET_DATA somewhere else in my ParentComponent like ComponentWillReceiveProps? The issue I had here is that maybe I'm doing something wrong, but it triggers an endless loop. Somehow though I feel that is the only place where I can address my need to dispatch GET_DATA after the local ParentComponent state is changed by setting refresh (a ParentComponent state variable) to true.
I think it would benefit you to refactor your actions a bit to take advantage of the action/middleware/reducer pattern.
You would have an action GET_TRANSACTIONS, that would take your year param. Your transactionsMiddleware would respond to the GET_TRANSACTIONS action by making your fetch request and would dispatch GET_TRANSACTIONS_SUCCESS with the respond data on success. You transactions reducer would then process the data into your store.
actions
export const getTransactions = year => {
return {
type: "GET_TRANSACTIONS",
year
};
};
export const getTransactionsSuccess = payload => {
return {
type: "GET_TRANSACTIONS_SUCCESS",
payload
};
};
middleware
function getTransactions(year) {
fetch().then(response => dispatch(actions.getTransactionsSuccess(response.data));
}
reducer
const getTransactionsSuccess = (state, action) => {
return Object.assign({}, state, newStuffFromActionPayload);
}
You would also have an action SAVE_TRANSACTIONS, which would be what your button would dispatch, along with the data to save. Your transactionsMiddleware would respond to the action by dispatching the update request. Your API would return the data from the updated record.
This is where you would have the middleware dispatch a follow-up action. It could be your getTransactions action, but it'd be even better to dispatch an action that your reducer would respond to by merging in the new data to your store.
actions
export const updateTransaction = payload => {
return {
type: "UPDATE_TRANSACTION",
payload
};
};
export const updateTransactionSuccess = payload => {
return {
type: "UPDATE_TRANSACTION_SUCCESS",
payload
};
};
middleware
function updateTransaction(transUpdate) {
fetch().then(response => dispatch(actions.updateTransactionSuccess(response.data))
}
reducer
const updateTransactionSuccess = (state, action) => {
find the record in the state, update it with data from action.payload
return Object.assign({}, state, updatedRecord);
}
If everything is set up correctly, it should trigger an update on your parent when it detects the change in the store. You avoid making two API calls for every save as well.
I have a state that specify which component render(component A or B).
This state is determined when my action dispatch specific type(for example GO_TO_B or GO_TO_A).
Then I need to fetch some config from server to render component A. I want these config be in store.So I should call a action(for example fetchConfig() ) to async fetch data from server and dispatch response.
My question is that where i call the fetchConfig() action.
if I call this action in componentDidMount() in component A the error occur that cannot dispatch middle of dispatch.
So which method in react life cycle call after dispatch process and before render ?
I understand you are using redux.
If that's correct, i recommend to do your fetching with a thunk.
redux-thunk is a middleware that allows you to dispatch functions (instead of serialized objetcs like actions), that way you can deley a dispatch of an action or even dispatch it conditionaly.
An example of a thunk would be like that:
function loadSomeThings() {
return dispatch => {
fetchFirstThingAsync.then(data => { // first API call
dispatch({ type: 'FIRST_THING_SUCESS', data }); // you can dispatch this action if you want to let reducers take care of the first API call
return fetchSecondThingAsync(data), // another API call with the data received from the first call that returns a promise
})
.then(data => {
dispatch({ type: 'SECOND_THING_SUCESS', data }); // the reducers will handle this one as its the object they are waiting for
});
};
}
You can notice we can even chain ajax requests and we can dispatch (if we want) an action on each success (OR FAIL!).
I recommend reading the docs to understand it better.
You can use componentWillMount : Doc.
componentWillMount() is invoked immediately before mounting occurs. It is called before render(), therefore setting state synchronously in this method will not trigger a re-rendering. Avoid introducing any side-effects or subscriptions in this method.