execute custom callbacks immediately after redux store update - reactjs

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

Related

Using react-redux, what is the best practice to pass a callback function to a generic Component through the redux state?

Here's a simple case, I want to create a generic Modal component with a confirm button. Once the button was clicked, it will fire the onConfirm function we provided via the redux state. And the openModal action can be dispatch inside a thunk action.
//Example using thunk after click submit a form
const handleSubmitForm = dispatch => e => {
dispatch(openModal({
title: "confirm modal",
onConfirm: () => { /* dispatch other stuff, async etc..)*/ }
}))
}
However, the issue is that the redux suggest not to pass any non-serializable value like function to the state. And when using redux-toolkit, it will generate a error message "A non-serializable value was detected in the state". So I wonder what is the best practice to perform this type of action.
Other use case:
dispatch a callback function to the state and contact a web socket server. Then the websocket server communicate back with something that trigger the callbcak.
Simple Modal CodeSanbox: https://codesandbox.io/s/black-mountain-wnytg?file=/src/containers/App.js
The best practice is not to do store any functions in redux (though it will technically work). Instead you should store whatever arguments you need to invoke the callback and use an action creator function to actually make the call. In your example you might store modalType, modalTitle, etc.

Redux and Redux thunk not synchronous

My assumption from working with redux is that dispatching actions is a synchronous task.
fire action 1 - > store updated
fire action 2 -> store updated
In a project I'm currently working on, I have a product customizer, that allows some user selection, they can place multiple orders, but if they're only ordering their current selection and select "purchase", I fire "addOrder", adding their selection to the orders array, and then the "purchase" action, which is a thunk submitting the orders stored in redux to my cart API.
I've expected that I would be able to rely on the store being in a consistent state, reliably after each action, and so when that second action fires it would have the state, as it is, after the first regular action fired before it, but no dice.
Are my expectations and understanding of redux here incorrect?
If so, Is redux thunk acting outside the normal dispatch in some way?
in my connected component I dispatch each action:
//.... inside component
purchase = () => {
this.props.addOrder(); // regular action
this.props.purchase(); // thunk
};
// ... rest of component
Yes, dispatching is always 100% synchronous, unless altered by a middleware. And yes, by default, you can call getState() again after a dispatch to get the updated state:
function checkStateAfterDispatch() {
return (dispatch, getState) => {
const firstState = getState();
dispatch({type : "FIRST_ACTION"});
const secondState = getState();
if(secondState.someField != firstState.someField) {
dispatch({type : "SECOND_ACTION"});
}
}
}

Dispatching new action after global state changes in react redux

Lets say i have a form where user is about to click on combination of buttons.
Each button triggers an action of type T and reducer R then updates its state and new combination is rendered on a website.
Now comes the tricky part:
I have my business logic implemented in reducer which applies new state which is about to be rendered. What i need now is when that state accepts a condition, i want to dispatch new action (api request).
What is the right approach to accomplish this kind of problem?
Set a flag into state, and call new action in component after?
Somehow dispatch a function in reducer?
...?
Redux Thunk allows you to dispatch multiple actions and dispatch asynchronous actions inside your action creators. For your scenario, you can do something like this:
function myAction() {
return (dispatch, getState) => {
...
dispatch(firstAction);
const state = getState();
// Check your state conditions from first action here.
dispatch(secondAction);
...
}
}
In this case you could use library redux-saga.
Using redux-saga, you'll be able to create a saga that you call from a component like actions. In the saga you will be able to call several redux-actions. If your state will be valid from the saga, you can call the API request.
A popular alternative to redux-saga is also redux-thunk.

Which method in react life cycle call after dispatch process and before render

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.

In React with Redux, when should I save data to back end

In React with Redux, when there are some user operations, e.g., in facebook, user adds some comments, I will call dispatch() to send the add action to redux store, but when should I call back end API to save these data to database? do I need to do it together with dispatch()?
thanks
One solution would be to transfer your API logic into a thunk using a middleware package such redux-thunk (or similar).
Using thunks allows you to treat special kinds of actions as functions which means you can extend a plain action with specific action-related logic. The example you give of needing to serialize your state is an excellent use-case for redux-thunk.
You should note that, unlike reducers, thunks explicitly support fetching state and dispatching subsequent actions via the getState and dispatch functions.
Below is an ES6 example of how such a multi-purpose thunk might look.
To demo the getState() method the new item will only be saved via the api only if the redux state shouldSave value is truthy.
I would also use the async/await syntax to make sure the the api call succeeds before dispatching the local redux action.
Thunk Example - adding a new item
import api from './api'
export const addNew = async (item) => {
return (dispatch, getState) => {
try{
const state = getState()
if(state.shouldSave){
await api.save(item)
}
dispatch({
type: ITEM_ADD_NEW,
data: item
})
}catch(err){
const error = new Error("There was a problem adding the new item")
error.inner=err
throw(error)
}
}
}

Resources