How to implement post api calls using thunk middleware in react-redux? - javascript

I was working with redux-thunk and superagent npm for jwt authentication and i would want to know how to implement post calls using thunk-middleware in the actions.js file and not in the main reducer.js file

There's a couple of different ways to go about it, but I personally like to use the axios library. Axios essentially just assists with making an API request and parsing the data back from the API into json.
In your actions.js file.
export const authenticateUser = () => {
return (dispatch, getState) => {
//get the token from the reducer
const jwtToken = getState().jwtTokenReducer.tokenKey
axios.post("/api/authenticate-user", jwtToken) //jwtToken passed into request
.then((res) =>){
dispatch({
type: "AUTHENTICATE_USER",
payload: res.data
})
}
.catch((errors) => {
dispatch({
type: "ERRORS",
payload: errors.response.data
})
})
}
}
So take a look at the above syntax. Typically when you define an action-creator, you setup a function that returns an action (object). But thanks to redux-thunk, you can now setup your action-creators to return functions with dispatch as an argument.
So in your returned function you can define certain logic, like making a request to an API like we did up there. Then we can take that data by using the .then promise handler and use it as a payload for an action that we would explicitly dispatch to our reducers.

Related

How to call second exported function from first exported on same js file

import * as endPointUrl from "EndPointUrls";
import axios from "axios";
First function : I just want ot call second function "loginAction()" from inside of first
export const verifyLoginAction = (loginCredential) => (dispatch) => {
const URL = endPointUrl.VERIFY_EMAI
axios
.get(URL)
.then((res) => {
loginAction(loginCredential)
});
};
Second Function:
export const loginAction = (loginCredential) => (dispatch) => {
const URL = endPointUrl.LOGIN;
axios
.get(URL)
.then((res) => {
console.log(res.data);
});
};
** I have attached Screen shot for each component**
This is my component, I am calling action
This is my action page, from component, I am calling "verifyLoginAction" and again on success of "verifyLoginAction" i am calling next function of same action page "loginAction"
on console view, i can see only log for "verifyLoginAction", call is not going for next function "loginAction"
So, I believe you are conflating a few things here. It appears that loginAction and verifyLoginAction are both being defined as thunks, in that they are not called directly but in a manner that returns a function that then accepts a dispatch-- usually this pattern is used in something like react-redux. So calling loginAction to actually execute the inner-function would require loginAction(loginCredential)(/*dispatch!?*/). That second function call is supposed to be passed dispatch, which would usually get stitched together in whatever library was being used. I suppose here it isn't critical as dispatch appears to never be used in the inner function; however, I am concerned that you are mixing patterns and bypassing your intended logic flow in a way that could yield unintended consequences down the road.

Is dispatch needed in an action in redux?

I've been learning redux for some time now and was wondering why is the dispatch needed in an action, cant we just use return, is that not the same thing?
return {
type: SEARCH_MOVIE,
payload: text,
};
};
export const fetchMovies = (text) => (dispatch) => {
axios
.get(`https://www.omdbapi.com/?apikey=${APIKey}&s=${text}`)
.then((response) =>
dispatch({
type: FETCH_MOVIES,
payload: response.data.Search,
})
);
};
The first action is without the dispatch and its working normally, why do we need to use dispatch in the other function cant we just use return? I just need someone to explain to me what dispatch does inside an action that im gonna dispatch anyway later in my component somehow or onClick.Why do we need to dispatch it twice?
That is a thunk when using the redux-thunk library.
With a plain basic Redux store, you can only do simple synchronous updates by dispatching an action. ...
Thunks are the recommended middleware for basic Redux side effects logic, including ... simple async logic like AJAX requests.
action, in the redux vocabulary, is just an object, e.g. {type: 'a1'},
action creator is a function that returns an action, e.g.
(value) => ({type: 'a1', valye})
thunk of action is a function that takes dispatch function as an argument and calls it, e.g.
(dispatch) => { dispatch({type: 'a1'}) }. With the redux-thunk middleware, it can be used in any place where action is expected.
thunk of action creator is a function (a) that returns a function (b) so that (b) is a thunk of action crated within a closure of (a), e.g.
(value) => (dispatch) => { dispatch({type: 'a1', value}) }
When using redux-thunk, the simple action creator and the thunk of an action creator can be used interchangeably, you don't have to use (dispatch) => ... when not needed (it is needed for asynchronous operations or more complex logic with multiple actions dispatched from one function).

Provide a Redux store to utility methods

I have a JS design question about how to provide a redux store to files that aren't react components. I have a typical react-redux application. Instead of calling fetch directly from my react components, I currently make all of my service calls in a centralized simple functional utility method file called fetches.js.
const mainFetch(uri, onSuccess, options) {
fetch(uri, options).then(response => {
onSuccess(response);
});
}
const export fetchDogs = (onSuccess) => {
mainFetch('/dogs', onSuccess, { method: 'GET' });
}
const export fetchCats = (onSuccess) => {
mainFetch('/cats', onSuccess, { method: 'GET' });
}
I realized that it'd be useful for my application to know exactly which of these requests we're currently waiting for. So I was thinking of adding this information to my redux state so that I could update mainFetch to look something like:
const mainFetch(uri, onSuccess, options, requestId) {
store.dispatch({type: 'STARTED_REQUEST', request: requestId);
fetch(uri, options).then(response => {
store.dispatch({type: 'FINISHED_REQUEST', request: requestId);
onSuccess(response);
});
}
But there's one problem, fetches.js has no access to the redux store. I could add a 'store' param to all of the methods in fetches.js, however I was thinking there'd be a better JS design pattern. Maybe initializing a class in App.js or something, similarly to how react-redux uses the Provider and 'connect' to provide the store to all child components. I'm new to JS so I was wondering how an experienced JS developer would solve this problem.
This design is lacking a middleware to handle the promises.
The basic idea is when you dispatch a Promise, from the code where you are 'calling' these 'fetch' functions, there would be a middle ware which would take the action dispatched and dispatch other actions such as 'Started fetching' and 'fetching ended' to mark the asynchronous flow.
A good start would be this link on the official site of redux - https://redux.js.org/advanced/asyncflow
A middleware - https://github.com/pburtchaell/redux-promise-middleware

Using redux best practice with promises

export function postRegister(credentials) {
console.log(credentials);
return dispatch => {
return fetch('/user/register', {
method: 'post',
body: JSON.stringify(credentials),
headers: {
'Content-Type': 'application/json'
}
})
.then(response => response.json())
}
}
I have few doubts regarding code above.
Can I use export () => {} instead of writing the word function here? Just to stay cleaner.
dispatch is a global variable? I did not see it's imported or required somewhere in the file.
Is specifying headers necessary here? I'm seeing that in every of the api call.
Why there's no catch in this promise call? Overall the code is bad?
No really, you could but you need a name to actually use it in your components.
No, dispatch is a parameter of the arrow function, you can also define getState to access the current redux state. By the way, you can totally assign new names if you want.
It depends on your server, but generally if you are using a JSON API, you would want to send that header.
Yes, overall that code doesn't look good, I would recommend using a middleware to handle the fetch requests, your actions should only send the configurations such as the url, body, method, etc... and your middleware should handle adding common headers (such as the content-type).
You could have an action like this:
export function postRegister(credentials) {
return {
types: [REGISTER, REGISTER_SUCCESS, REGISTER_FAIL],
promise: {
url: '/user/register',
data: credentials,
},
};
}
Something as simple as that, then your middleware should do the fetch and dispatch the action types based on the server response.
If you want to know more about how the middleware should handle the fetch request and dispatch the actions, make sure to take a look at my post here: https://stackoverflow.com/a/39971763/146718
not unless it is export default. since later u will need to import it by name.
no, dispatch is an argument that is passed to your function:
(dispatch) => {}
Totally depends on your application, server, request, etc.
you could add .catch((e) => {}) your self, or use some interceptors for generic errors, do a dipatch from there and add a reducer which will handle these actions. you could read more here:
What is the best way to deal with a fetch error in react redux?

Redux async actions based on login

I have the following action in my actions.js file. But I get the error "Actions must be plain objects. Use custom middleware for async actions." I'm assuming it's because I putting the return in a weird place. Any ideas?
export function loginLookUp(credentials) {
const request = axios.post(`${LOGINLOOKUP_URL}`, credentials).then(function (response) {
return {
type: LOGIN_SUCCESS,
payload: true
};
})
.catch(function (error) {
return {
type: LOGIN_FAIL,
payload: false
};
});
}
Your action creator doesn't return anything - your return statements are in the scope of the promise callbacks, not the surrounding function. But that's kind of beside the point - even if you did return the promise from the action creator, Redux wouldn't know what to do with it!
In order to do asynchronous actions, you need to use a library such as redux-thunk or redux-promise. I'm not going to go into detail on how to set these libraries up, as the READMEs on their repos do a much better job, but here's a few examples of how you'd use them.
redux-thunk allows you to dispatch a function that in turn has access to dispatch, like so:
export function loginLookUp(credentials) {
// This would look a lot cleaner if you used an ES2015 arrow function
return function (dispatch) {
const request = axios.post(`${LOGINLOOKUP_URL}`, credentials).then(function (response) {
dispatch({
type: LOGIN_SUCCESS,
payload: true
});
})
.catch(function (error) {
dispatch({
type: LOGIN_FAIL,
payload: false
});
});
}
}
This is about as simple as async actions get, and it's how the official Redux tutorial will teach you to do it - make sure to give those chapters a read, it's really helpful stuff!
redux-promise, on the other hand, lets you dispatch actions with a promise as the payload:
export function loginLookUp(credentials) {
return {
type: LOGIN,
// Payload must be a promise!
payload: axios.post(`${LOGINLOOKUP_URL}`, credentials)
};
}
Rather than the action immediately being passed to the reducer, it will use .then() to wait for the promise in the payload to complete. Then, it will dispatch the action in one of two forms.
If the promise resolves, the action will be dispatched with the payload set to the resolved value, like so:
{
type: LOGIN,
payload: // The response from the server
}
If the promise fails, the action will be dispatched with the payload set to the rejected value and the error property set to true, like so:
{
type: LOGIN,
payload: // The error object,
error: true
}
These are by no means the only ways of doing things - there's countless async action libraries, so if these both made you recoil in horror, there's bound to be something else that will suit you (I hear really good things from people smarter than me about redux-saga, but I can't comprehend it myself)!
Talking of sagas, this answer ended up being way longer than I intended. Hopefully it clears stuff up for you!

Categories