Using promises in react-redux actions dispatch functions? - javascript

I am new to react-redux . I want to know is this ok to use ES6 promises with actions dispatch functions ? Suppose i want to show success toast after request success . What i did is resolve promise when request hit successfully.See example code below
#Example
function login(credentials){
return dispatch => {
return new Promise((resolve,reject)=> {
dispatch(login_request);
service.login(credentials)
.then(
(data)=> {
dispatch(login_success,data);
resolve();
})
}) }}
Then calling that function from UI what i did,
login().then(success => show_toast());
Is this approach OK to show toast?

Technically it's fine, though personally i think its unnecessary to chain to this promise.
You already dispatching an action inside your thunk login_success, so you can use this as a condition to show the toast

Related

JavaScript: Promises and RxJS - subscribe() same as then()?

Problem
I am currently working on UI and I use React. Inside of the .jsx component, I have everything : HTML (JSX), JavaScript-Logic, and API calls. Everything in one file, this gets messy.
Goal
I would like to outsource functionality, so I created a class that should handle all API-Calls. I also would like to use RxJS and combine axios with RxJs.
Code
What is happening in the the code? I have a class ApiCalls that contains a static method putApiCallExample. There I do the api call but creating a Promise with axios. I use the from() functionality form rxjs to create an observable and inside the pipe i return the data.
In the Main.jsx I am using this in the useEffect()-hook, I subscribe on it and set the State based on it.
class ApiCalls:
static putApiCallExample(URL, data){
const promise = axios
.put(URL, data, {
headers: {
"Content-Type": "application/json"
}
});
return from(promise).pipe(map(res => res.data));
}
const Main = () => {
const [show, setShow] = useState(false);
useEffect(() => {
ApiCalls.putApiCallExample().subscribe(
res => {
console.log("1", res);
setShow(true);
},
err => {
console.log("2", err)
}
);
}, [])
}
Question
Can I interpet the subscribe() functionality as same as .then() from axios ?
Do I need to unsubscribe here?
Does this cause performance issues to mix axios and rxjs?
I assume that if you use Axios, you don't need to receive multiple response from the server like for SSE or websocket. So:
Can I interpet the subscribe() functionality as same as .then() from axios ?
In a way, yes, the observable subscribe callback is triggered when Axios promise resolves. Then it will not be triggered anymore, so in this specific case, the RxJs observable behaves the same way as the Axios promise.
Do I need to unsubscribe here?
As the Observable can't be triggered more than 1 time, I don't see any reason to unsubscribe.
Does this cause performance issues to mix axios and rxjs?
You're only wrap Axios promise into a RxJs observable. This RxJs wrapper will not have a significant memory or CPU blueprint.
By the way, this is basically what's Angular Http client is doing internally. My opinion is that it's safe, but it doesn't bring too much value either.

Problem with reading data from Cache API (still in promise?)

That is my first post here. I am not well skilled in asynchronous code so can not resolve the problem by myself
In a React/Redux app I have added cache. The idea behind it is to have something like 'Favorites' functionality but on clients' computer. So, I would like to store over there some data about books. While writing to cache works I can not successively dispatch data to store> Now my code looks like this:
export function fetchFromFavorites() {
return async (dispatch, getState) => {
const URL = getState().books.currentURL;
const Cache = await caches.open(URL);
Cache.matchAll()
.then(function (response) {
const ar = [];
response.forEach(async item => ar.push(await item.json()));
return ar;
})
.then(response => dispatch(test(response)));
};
}
In the code above test is an action that only sets the state field with payload. While the payload can be log-consoled from reducer, I can not perform on that any further action with another external function, well-checked on that kind of data. Besides DevTools mark it with blue 'i' what indicates that it has been calculated very lately. What is wrong with that code? BTW - it has nothing to do with service workers it is just inside regular React.
The function you are passing to response.forEach is returning a promise. You'd need to wait for all of those promises to resolve before returning ar.
For example, you may use something like:
// await all promises to be fulfilled before proceeding.
// note that we use response.map instead of forEach as
// we want to retain a reference to the promise returned
// by the callback.
// Additionally, we can just return the promise returned
// by `item.json()`
await Promise.all(response.map(item => item.json());
Remember, any function marked as async will return a promise wrapping the function's return type.
Note that you're mixing async/await with older style then/catch promises here. For consistency and ease of reading, you may want to use one style consistently.

How can I make a statement wait until a previous function is finished?

I've got an issue where window.open gets called too quickly and my other function doesn't finish and post in time in my onclick function.
I tried setting a timeout on the trackData() but it only worked on occasion and I didn't want to set a longer timeout.
onClick
{() => {
trackData();
window.open("https:google.com", "_self");
})
any ideas?
EDIT: The following works locally but doesn't track when in production. Tracking works EVERYTIME if "_self" is being replaced with "_blank" (which it cannot be)
let postData = async(value) => {
await tracker({
action: value,
})
}
tracker just makes an axios post with the action
<div
className="exampleBTN"
onClick={() => {
postData("example").then(
window.open("https://google.com",
"_self")
)}
}
>
</div>
Locally, I can see the data going into the database.
However, online it doesn't work. It only works if either of these are true:
Doesn't have window.open in the onClick
doesn't have "_self" but "_blank" so it opens in a new tab
I thought my async was wrong so I also tried the following:
onClick={async () => {
await postData("example").then(
window.open("google.com", "_self"))
}}
You can work with .then or async/await to do exactly this when action results in a Promise. Axios requests return Promises.
initiateAsynchronousAction()
.then(result => console.log(result))
Callback inside the .then function will only be executed if the promise is fulfilled by the action executed by the async function.
Minor clarification:
Note that inside the .then() you have to pass a callback function and not just immediately invoke actions you want to perform, even if you don't plan to use the result value. So it will be
.then(result=> console.log('Inside callback!'))
and not
.then(console.log('Inside callback!'))
Async-await is another way to write this, it is simply syntactic sugar, that is just an easier way to write it:
const foo = async () => {
const result = await initiateAsynchronousAction()
console.log(result)
}
The variable result will only be given the value once the Promise is resolved. That is, the assigning of the value will be awaited.
You can chain a .catch in the first case or envelop the task in a try-catch block to catch errors if the Axios promise is unfulfilled.
you can use promise based approache here.use aysnc and await for that.
async function trackData(){
.....
let data = awiat your code
.....
}
function call with promise
trackData().then(res=>{
if(res ==="Success){
window.open("https:google.com", "_self")
}
})

How to create async/await structure for two redux actions?

I have two actions on button change function which are dependent on one another. What I want to do is I want to put these two function in async/await structure so that after update_other_filter action ends, that I will be able to run getTotalData action. Running it like below structure actually does not update state in correct way. I am sending previous state(before update_other_filter) in getTotaldata.
You guys will probably say I have to dispatch getTotalData inside update_other_filter action when it resolves. But in this state of my project it seems I can not change anything. I am not really good with async/await and promises concept so, I only want to create async/ await fucntion inside my react component than I want to call it inside onChange function. Is there a way to do that?
onChange = {(event) => {
this.props.setSpinner()
//this update filter function updates filter which will be sent to server in getTotalData action
this.props.update_other_filter(true,"website",!event.target.checked)
//this action should wait for update_other_filter to end than it has correct parameters to send to server
this.props.getTotalData(this.props.totalFilters, apiUrl)
}
async onChange = {(event) => {
this.props.setSpinner()
await this.props.update_other_filter(true,"website",!event.target.checked)
this.props.getTotalData(this.props.totalFilters, apiUrl)
}
// I will make function wait that needs for dependent function and also add some error handling.
async onChange = {(event) => {
this.props.setSpinner()
try
{
await this.props.update_other_filter(true,"website",!event.target.checked)
this.props.getTotalData(this.props.totalFilters, apiUrl)
}
catch(e)
{
thorw e;
}
}

Why does redux thunk return promise?

I am learning redux-thunk middleware as a beginner react developper, and I don't understand why dos the function (returned by redux-thunk) returns a promise (returned by fetch())
I tried not to return anything, and it worked, so why do we return it?
export function getCourses() {
return fetch(baseUrl)
.then(handleResponse)
.catch(handleError);
}
export function loadCourses() {
return function(dispatch) {
dispatch(beginApiCall());// dispatch some synchronous action
return courseApi
.getCourses().then(courses => {
dispatch(loadCourseSuccess(courses));
}).catch(error => {throw error;});
};
}
For the component named MyComponent dispatching loadCourses() action
function MyComponent(props){
.......
useEffect(() => {
loadCourses()
});
const mapDispatchToProps = {
loadCourses,
.....
}
}
I think i got the answer(from a colleague).
if you want to chain certain activities, your action would need to return a Promise.
it's just a good way to allow chaining activities after the result is returned!
Well, first of all the function returns some data because you asked it to return some sort of result return function(dispatch) {...}.
If you want to ignore the returned result just remove the return from return function(dispatch) {...}.
Secondly, the function returns a promise because of the way that you have written your call to API functions (wrapped inside promise and not returning callbacks upon function completion).
If you want to get the actual result of the API call you should use the Async / Await syntax.
With a plain basic Redux store, you can only do simple synchronous updates by dispatching an action. Middleware extends the store's abilities and let you write async logic that interacts with the store.
Thunks are the recommended middleware for basic Redux side effects logic, including complex synchronous logic that needs access to the store, and simple async logic like AJAX requests.https://github.com/gaearon/redux-thunk
The thunk middleware knows how to turn thunk async actions into actions, so you just have to have your simple_action() to be a thunk and the thunk middleware will do the job for you, if the middleware see a normal action, he will dispatch this action as normal action but if it's an async function it will turn your async action into normal action.
You can also see return promise from store after redux thunk dispatch

Categories