suppose if i dispatch an action using dispatch() , i know that reducer() is called which has an action object and current state as parameters . i want to know what calls that reducer function ? which functions are called before reducer function and after dispatch function ? after reducer function returns the new state ,which functions are called after that ? where does this new state goes ? does usestate() and useselector() also returns something after reducer function returns new state ?
i want to know what calls that reducer function ?
which functions are called before reducer function and after dispatch function
dispatch() indeed 'call' every reducers. It uses an event system and all reducers are listening to this event (this is all behind the scene).
Still, you can write a piece of code that will be inserted between the dispatch call and the reducers catching actions.
It's called a middleware.
A middleware can intercept any action triggered by a dispatch, also it has access to the store.
At the end of your middleware your just use a callback to tell the flow to continue.
You need to pass your action to it so your reducers can finally be called and receive the action.
Here is an example of middleware that log any actions that are sent by any dispatch()
const logger = store => next => action => {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
To make it work you need to pass your middleware to your redux configuration, so they can be called.
after reducer function returns the new state ,which functions are
called after that, where does this new state goes ?
If you look at your redux configuration you'll see somewhere that you combine all of your reducers ( often called root reducer).
const combinedReducers = combineReducers({ reducerA, reducerB })
const store = createStore(combinedReducers )
Redux use this combination of reducers to fill the store, so anytime a reducer return it's result, it can be save in 'the store'
does usestate() and useselector() also returns something after reducer function returns new state ?
useSelector() is a hooks that has the ability to read in the store. (Store that contains the fresh result of your reducers and is updated every time there is a modification in the store)
useState() is not related to redux. It's related to React. With useState you can read and write in the local state of a component.
It returns you a piece a your state and a setter for this piece of state.
const {myPieceOfState, setMyPieceOfState} = useState({ something :'a default value for myPieceOfState'})
Related
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]
I am new to react and redux. I have gone through many online tutorials on react redux but still not able to understand how action and reducer is connected. If I am right, we import action in container/component, we import reducer in a file where we create a store. So there is a connection between container - action, and there is a connection between reducer and store but in action file we dont import reducer. So how action is connected to reducer. I know that we have a type of action which will be checked in switch case in reducer. But how does it get passed to reducer.
Very High Level Overview
Action - Actions can update state
{ type: ACTION_TYPE, somePayload: payload }
The redux store exposes out a dispatch function, that ultimately wraps an action creator.
mapDispatchToProps = dispatch => {
return {
someWrappedAction: () => dispatch(actionCreatorFn()),
someOtherWrappedAction: val => dispatch(otherActionCreatorFn(val)),
}
}
useDispatch Hook returns the dispatch and you wrap action yourself
const dispatch = useDispatch()
<button onClick={() => dispatch(someActionCreatorFn())}>
Do Action
</button>
Reducer
The reducers form a state tree, starting with the root reducer passed to the redux store. The "connection" is made (conventionally) via the mapDispatchToProps and connect HOC. (Now can get the dispatch from useDispatch hook)
Reducers are pure functions that take two arguments, current state and an action, and returns the next state.
(currentState, action) => nextState
So how is each dispatch in mapDispatchToProps connected to the appropriate reducer...
When you dispatch an action creator it passes the action object to the root reducer. The action object is passed through the entire state tree and any reducers that process the action type consume it.
TLDR: dispatch function takes action as an argument and calls currentReducer(..., action).
When you call creteStore(reducer), the returned object contains dispatch and subscribe functions.
When you (or react-redux library) call subscribe(listener), redux will remember your listener function (in case of React, the listener has to make sure the component re-renders with new props, context, state, or refs - depending on concrete implementation).
When dispatching an action with dispatch(action), the dispatch function will call reducer(action, state), modify redux internal currentState then call each listener().
I am little confused about behaviour when I dispatch redux action.
Example:
onPressAdd() {
this.props.addFloor({
name: this.state.floor_name,
});
console.log(this.props.floors);
}
I am calling redux action addFloor what adds floor into array in store, then I console.log this variable and I expecting updated state ([{name:'whatever'}]) but I am getting [] (empty array)
Example 2:
async onPressAdd() {
await this.props.addFloor({
name: this.state.floor_name,
});
console.log(this.props.floors);
}
In this example I am getting perfectly fine updated store: [{name:'whatever'}]
I am reading everywhere that "Redux actions dispatch is sync if there is no thunk or saga (Direct way: dispatch action->reduce->store", but rhis is proof that dispatches are ASYNC.
So where is truth?
Dispatching by itself is 100% synchronous.
This is a tiny implementation of a Redux store:
function createStore(reducer) {
var state;
var listeners = []
function getState() {
return state
}
function subscribe(listener) {
listeners.push(listener)
return function unsubscribe() {
var index = listeners.indexOf(listener)
listeners.splice(index, 1)
}
}
function dispatch(action) {
state = reducer(state, action)
listeners.forEach(listener => listener())
}
dispatch({})
return { dispatch, subscribe, getState }
}
By the time dispatch() returns, the store has executed your reducer function, and called all the store subscriber callbacks.
It's only when you start adding middleware into the store that the dispatching process can be interrupted, because any middleware can delay, stop, or rewrite any action that was dispatched.
What you're seeing in that example is actually based on how React works. Inside of that click handler, React has not yet re-rendered and updated the props of the component, so this.props.whatever will still be the same before and after the dispatch.
The key thing is to realise that React doesn't update the props of your component until the execution of a called handler is not finished as a macrotask. Hence, your console.log after dispatch doesn't have updated props yet.
Roughly saying, doing your Example 2, you simply split it and get a new microtask with all included after await line, which will be executed after the props are updated.
That would be the same if you do Promise.resolve(this.props.addFloor(...)).then(() => console.log(this.props.floors)) without async/await.
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"});
}
}
}
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.