Redux action dispatch - reactjs

In my redux action, I have one action will be called by another two actions, code is below:
export const addParticipantFromPopupRequest = (participant, project_id, currentStep) => async (dispatch) => {
const result = await addParticipant(participant)
dispatch({ type: PARTICIPANT_ADD, payload: result })
dispatch(updateProjectStep(project_id, currentStep))
}
export const handleFinalStep = (projectId, currentStep) => async (dispatch) => {
dispatch(updateProjectStep(projectId, currentStep))
}
const updateProjectStep = (projectId, currentStep) => async (dispatch, getState) => {
dispatch({ type: MODAL_STATUS_CHANGE, payload: { projectId, currentStep } })
dispatch({ type: PROJECT_PROCESS_LIST_UPDATE, payload: { project_id: projectId, currentStep } })
const { projectsProcessListsReducer } = getState()
localStorage.setItem("projectsProcessLists", JSON.stringify(projectsProcessListsReducer))
}
If I dont' use dispatch when call updateProjectStep, the addParticipantFromPopupRequest and handleFinalStep cannot run correct.
My question is can I call dispatch actions in this way and is it correct? Why I need the "dispatch" when I call updateProjectStep in another actions rather than call function name directly?

My question is can I call dispatch actions in this way and is it correct?
Yes. You should always call with the dispatch.
Why I need the "dispatch" when I call updateProjectStep in another actions rather than call function name directly?
If you call updateProjectStep directly without dispatch, it will become a normal js function call and your store won't be aware of it. Dispatch is the only way to trigger a state change in store.
In redux the store is single source of truth, the dispatch you are using is actually comes from store (store.dispatch).
If you call a function normally then it won't be aware by the store. That action won't pass through the middlewares (thunk/saga) that store is aware of and won't do the store update via reducers.
If store is not updated, your components won't receive any updates. Eventually your UI won't re-render.
You can find more about dispatch here.

Related

Dispatching Redux-Toolkit Actions in other Actions

so i'm new to redux-toolkit and this is my final goal: to dispatch an action which updates loading state, and then call the login function, after this is done successfully dispatch another action which again updates the loading state, how can i achieve this considering i need to update (dispatch) the loading action for almost every reducer i have?
i know that in redux i can simply use dispatch in the function as my second argument and then use it but im not familiar how this works in redux-toolkit.
this is my code in redux:
export const login = (model) => (dispatch) => {
dispatch(isRequesting());
return (
authService
.ssoLogin(model)
.then((result) => {
dispatch(ssoIsAuthenticated());
localStorageService.setKey(storage_key.is_auth, true);
dispatch(isRequested());
history.push(routes.home);
})
.catch((error) => {
utilService.handleError(error);
dispatch(errorOccurred());
})
);
};

How does dispatching a action creator function work?

Say I have a action creator function like the one below:
import {v4 as uuidv4} from uuid;
export const doSomething = (task) => (dispatch) => {
dispatch({
const id = uuidv4();
dispatch({
type: "SET_TASK",
payload: {id, task}
})
})
}
What is the logic behind having to wrap it in a dispatch method when I am calling it to update the state of a store in another action creator function?
i.e.:
import {setAlert} from "./doSomething"
// another action creator
export const anotherActionCreator = () => dispatch => {
...
dispatch(doSomething("Laundry"));
...
}
When I remove the dispatch method wrapping, it would not call the reducer and update the state in the redux store. I am thinking the action is somehow not connected to the store, but I don't understand how. I thought when you call doSomething("Laundry"), the dispatch inside it will already update the store -- but somehow it didn't -- why is that?
By default, the Redux store only understands how to accept plain action objects passed to dispatch, like:
store.dispatch({type: "todos/todoAdded", payload: "Buy milk"};
If you pass a function to dispatch(), the store will throw an error.
However, middleware wrap up the dispatch function, and can intercept whatever's been passed in to dispatch(). This allows middleware to "teach the store how to accept non-action values", such as passing a function to dispatch(someFunction).
This is how the redux-thunk middleware works. It looks for anything that is actually a function instead of an action object, intercepts that function, and calls it.

React trying to pass async call into Props

So what I'm trying to do is basically call an async function than ask mapStateIntoProps to pass it into props into the actual component. When I do I get a console.log() that shows pending my data is in there tho.
here is my first file that has the async func
export const getIdMovie = async (state,movieId)=>{
let data= await axios
.get(
`https://api.themoviedb.org/3/movie/${movieId}?
api_key=${APIKEY}&language=en-US`
)
let results=data.data
return results
}
this is where i try to call it on the second file
injectDataReducer(store, { key: "movie", reducer: MovieReducer });
const mapStateToProps = (state, ownProps) => ({
movie: getIdMovie(state,ownProps.movieId)
});
If getIdMovie is an action creator, you will have to use redux-thunk.Reducer updates the store asynchronously when you dispatch and action to avoid changing same data by multiple dispatch actions.
````Also, you will have to first set the state i.e. movies into reducer and then update the data from there into your component.```

Purpose of Redux Thunk `([arg(s)]) => dispatch =>`?

The code below comes from a Udemy course on the MERN stack by Brad Traversy. I'm new to Redux and Redux Thunk and am trying to understand what the purpose of => dispatch => is. I know it comes from Redux Thunk, which was set up in the Redux store file. I think dispatch is being used here in order to dispatch more than one action from this function and read that the = ([arg(s)]) => dispatch => syntax is an example of currying (though that doesn't seem right since with currying each function has one argument).
I'd greatly appreciate any help understanding => dispatch =>.
(Other minor point of confusion: In the course the function setAlert is referred to as an action, but I'm not sure that's correct since it contains multiple dispatches of actions.)
export const setAlert = (msg, alertType, timeout = 5000) => dispatch => {
const id = uuidv4();
dispatch({
type: SET_ALERT,
payload: { msg, alertType, id }
});
setTimeout(() => dispatch({ type: REMOVE_ALERT, payload: id }), timeout);
};
There's a couple of things going on here:
1) setAlert is what is usually called an "action creator". It's a function that returns an action that you can dispatch later.
2) Redux-Thunk is allowing you to use functions of the form (dispatch) => {} as actions (in place of the more normal object form { type, payload })
It might help if you look at them individually before seeing how they combine together:
// This is an action creator (a function that returns an action)
// This doesn't use redux thunk, the action is just a simple object.
// Because it's an action creator you can pass in arguments
// Because it's not a thunk you can't control when then dispatch happens
const setAlertActionCreator = (msg, alertType) => {
const id = uuidv4();
return {
type: SET_ALERT,
payload: { msg, alertType, id }
};
};
// You use this as:
dispatch(setAlertActionCreator("msg", "type"));
// This is not an action creator it's just an action.
// This IS a redux-thunk action (it's a (dispatch) => {} function not a simple object)
// Because it's not an action creator you can't pass in arguments to get a custom action back
// Because it IS a redux-thunk action you can dispatch more actions later
const setAlertThunk = (dispatch) => {
setTimeout(() => dispatch({
type: SET_ALERT,
payload: {
message: "fixed message",
alertType: "fixed alertType",
id: "fixed id",
}
}), 5000);
};
// You use this as:
dispatch(setAlertThunk);
// When you combine both patterns you gain the ability
// to both pass in arguments and to create additional dispatches
// as the function runs (in this case dispatching again after a timeout.)
// I won't repeat your code, but will show how you would call it:
dispatch(setAlertActionCreator("msg", "type"));
// ie: you use it the same way as example 1.
The syntax () => dispatch => is equivalent to:
function response(){
return function (dispatch){
//Some code here
}
}
So, basically what you can say is, it is a modern way of writing the same function. => dispatch => is returning a function that will be executed when the action will be invoked.
Hope this will help.
=> dispatch =>
is nothing but a syntactical sugar over a function returning another function. Since Fat-arrow functions => are used in place of normal functions.
Like
function abc(a,b){
return a+b;
}
is same as const abc = (a,b) => a+b ;
So you dont have to write return keyword.
So in your case its the same => dispatch => and the one below , its returning an anonymous function with . dispatch as its arguement
function response(){
return (dispatch){
//some code here
}
}
Hope it helps, feel free for doubts

If an action needs to use some current state, who should fetch it from store?

The title may not clear enough, please consider this example:
If I have a data table, which you can select multiple rows, and click action button like delete.
now in my actions.js:
(selectedRows is an array that contains the row indexes, getSelectedPostIds is a selector which will fetch and convert selectedRows to postIds)
import { getSelectedPostIds } from 'selectors'
export const deletePosts = () => (dispatch, getState) => {
// encapsulate the parameter `postIds` in action
const postIds = getSelectedPostIds(getState())
dispatch({ type: 'DELETE' })
deletePostsApi(postIds)
// .then(...)
// .catch(...)
}
is there any problem in this design? Or I should avoid using getState in an action and just pass postIds as a parameter to the action:
export const deletePosts = postIds => dispatch => {
dispatch({ type: 'DELETE' })
deletePostsApi(postIds)
// .then(...)
// .catch(...)
}
The only difference is that who should fetch the state (use the selector) from store, 1. action or 2. the component who will dispatch the action (via mapStateToProps).
I'm not sure about the approach 1, and the approach 2 will make my component contains a lot of props just because some actions need them (or maybe this is totally fine?).
thanks.
This might be a matter of taste. I usually like to access getState directly since, as you point out, avoids passing a lot of props. And by doing that the action is easier to integrate in different components (I just need to call it instead of additionally editing the mapStateToProps). Also, since in the end both ways are accessing the global store, the intended redux data flow is not compromised in any way.
You can use redux-thunk if you want to work with state in your action creators. :)
https://github.com/gaearon/redux-thunk
function yourActionCreator() {
// Redux-thunk will catch all action creators that return functions
return (dispatch, getState) => {
// u can use state here
const { counter } = getState();
if (counter % 2 === 0) {
return;
}
// Dispatch your action creator as you would normally do
dispatch(increment());
};
}

Resources