How does action creator which is a thunk receive a store's dispatch method? - reactjs

I am learning redux and there is one thing puzzling me regarding the internal logic - how does a thunk receive dispatch as argument if a thunk is an argument to dispatch and not vice versa? Here is a sample code:
I am creating an action creator which is a thunk (it does not return an action itself but another function which eventually returns the action). I am defining it to receive dispatch function as argument, like this (code is simplified to serve as example):
export const fetchPosts = () => {
return async (dispatch) => {
const response = await fetch('some url');
dispatch({type: 'FETCH_POSTS', payload: response});
}
}
Then I use this thunk in App.js file, when I am getting a dispatch function from 'react-redux':
import { useDispatch } from 'react-redux';
import { fetchPosts } from './store/posts-actions';
function App() {
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchPosts());
},[dispatch]);
...
}
I am not passing dispatch as an argument to fetchPosts(). I am passing fetchPosts() to dispatch. And this is the part that I don't understand.
How does fetchPosts receive dispatch as argument if fetchPosts is an argument to dispatch and not vice versa?

This is covered in the Redux docs pages on Writing Logic with Thunks and Redux Fundamentals, Part 6: Async Logic and Data Fetching.
The Redux thunk middleware looks for any time that a function gets passed into dispatch, intercepts that function, and then calls it with (dispatch, getState) as arguments:
// standard middleware definition, with 3 nested functions:
// 1) Accepts `{dispatch, getState}`
// 2) Accepts `next`
// 3) Accepts `action`
const thunkMiddleware =
({ dispatch, getState }) =>
next =>
action => {
// If the "action" is actually a function instead...
if (typeof action === 'function') {
// then call the function and pass `dispatch` and `getState` as arguments
return action(dispatch, getState)
}
// Otherwise, it's a normal action - send it onwards
return next(action)
}

Related

Not understand the code of action and dispatch in this Redux tutorial

I'm watching a tutorial about MERN stack project of a youtuber. And I'm watching him coding the Redux part of the project. There is some of his code which I don't understand
This is his Redux action code to retrieve data from api
From what I understand, this is an action and it supposed to return action object {type, payload}. I don't understand why he give an dispatch argument in the curly braces (line 4) and dispatch the action object (line 8)
This is his App.js file
And in his App.js I dont see him pass any argument into getPosts() (line 16)
I try to create action using redux toolkit like this
export const getPosts = createAction('FETCH_ALL', async () => {
try {
const { data } = await api.fetchPosts();
return {
payload: data,
};
} catch (error) {
console.log(error.message);
}
} )
Is there anything difference between my code and the image code
URL to the video : https://youtu.be/ngc9gnGgUdA?list=PL6QREj8te1P7VSwhrMf3D3Xt4V6_SRkhu&t=3130
It is a thunk function from redux-thunk. A thunk function is a function that accepts two arguments: the Redux store dispatch method, and the Redux store getState method. Thunk functions are not directly called by application code. Instead, they are passed to store.dispatch():
const thunkFunction = (dispatch, getState) => {
// logic here that can dispatch actions or read state
}
store.dispatch(thunkFunction)
Reference: https://redux.js.org/usage/writing-logic-thunks

Redux Action Creator and Dispatch confusion with syntax

I'm having some trouble understanding this productListCreator syntax. Using thunk, the tutorial I'm following says that thunk allows us to write the an async function within a function.
productListCreator is a function that returns async function with dispatch as an argument.
But when you use call/use this with dispatch(productListCreator()), I'm confused.
productListCreator has no dispatch argument being passed. Instead it is being passed into the useDispatch hook.
So to me the code is saying useDispatch() which takes productListCreator function and runs it, which has no argument passed in for "dispatch".
import axios from 'axios'
const productListCreator = () => async(dispatch) => {
try {
dispatch({
type: 'PRODUCT_LIST_REQUEST'
})
const { data } = await axios.get('/api/products')
dispatch({
type: 'PRODUCT_LIST_SUCCESS',
payload: data
})
} catch (error) {
dispatch({
type: 'PRODUCT_LIST_ERROR',
payload: error.message
})
}
}
export default productListCreator
const dispatch = useDispatch()
// Retrieve all products at reload
useEffect(()=>{
dispatch(productListCreator())
},[])
productListCreator is a "thunk action creator". It defines the "thunk function", and returns it. That "thunk function" is what gets passed to dispatch. The thunk middleware then intercepts the thunk function, calls it, and passes in (dispatch, getState) as arguments.
I'd recommend reading through the new "Writing Logic with Thunks" docs page, which explains how thunks work.

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

How are getState and dispatch imported in redux-thunk action creator?

import _ from 'lodash';
import jsonPlaceholder from '../apis/jsonPlaceholder';
export const fetchPostsAndUsers = () => async (dispatch, getState) => {
await dispatch(fetchPosts());
_.chain(getState().posts)
.map('userId')
.uniq()
.forEach(id => dispatch(fetchUser(id)))
.value();
};
export const fetchPosts = () => async dispatch => {
const response = await jsonPlaceholder.get('/posts');
dispatch({ type: 'FETCH_POSTS', payload: response.data });
};
In the above code getState and dispatch functions are passed as arguments to the action creator function, what i m puzzled about is why are these functions not imported from anywhere or does react/redux somehow import them for us?
ok I will try to clear your confusion,
As you know action creators returns plain javascript object, but thunk is a middleware which allows you to return function instead of plain javascript object from the action creators, so when you use thunk if you return plain javascript object from action creator its handled in normal way, but when you return a function from action creator than thunk handle it and call this function with dispatch and getState, so you can dispatch an action asynchronously, you are not passing these arguments, see it this way that you are returning a callback from action creator and thunk call this callback with these arguments.
Hope it helps.
When you connect a react component with redux using a connect function provided by redux you will pass in to functions: mapStateToProps and mapDispatchToProps. Those will be the parameters your looking for (dispatch and getState).
Thunk is a function which optionally takes some parameters and returns another function, it takes dispatch and getState functions, and both of these are supplied by Redux Thunk middleware

Redux getState in action not working

I'm getting a bit confused with getState() in redux. I am using the thunk middleware.
I have an auth action which is an async action. But I have an action which runs before which checks if a token exists in state and if its still valid.
My problem is i can't seem to check the state when I have called the action. Thought I could just use getState but that doesn't seem to be a function.
container.js
componentDidMount() {
this.props.authCheck()
}
...
function mapDispatchToProps(dispatch) {
return {
authCheck: () => checkApiStatus()(dispatch)
}
}
Action.js
export const checkApiStatus = () => (dispatch, getState) => {
const expires_at = getState().api.expires_at
if (!expires_at || isDateGreater(expires_at)) {
// dispatch async action
dispatch(apiAuth())
}
return
}
Anyone have any ideas. Or perhaps better way of implementing something like this?
Thanks
The problem is you explicitly calling the returned function in you mapDispatchToProps method and passing only one argument. Instead call dispatch(checkApiStatus()) then redux-thunk will take care of passing the right arguments to the returned method. Should look like this
function mapDispatchToProps(dispatch) {
return {
authCheck: () => dispatch(checkApiStatus())
}
}

Resources