While going through the Redux middleware, I have come across Axios which is 'Promise-based HTTP client' to make Ajax request from browser. Could any body explain about this term and some info about axios?
Before Promise's comes into the picture there is something called Callback to handle asynchronous calls/code. But the main issue with callback is that when it gets nested and more nested it becomes very messy code and harder to understand even for the writer of the code.
To make it bit cleaner Promise comes into the picture which is cleaner in nature, Avoid callback hell problem in nodejs programming.
Moreover the concept async/await is also best fit with the promise instead of callback.
Hope you understand now. Comment below in case of any doubt.
From MDN:
A Promise is a proxy for a value not necessarily known when the
promise is created. It allows you to associate handlers with an
asynchronous action's eventual success value or failure reason. This
lets asynchronous methods return values like synchronous methods:
instead of immediately returning the final value, the asynchronous
method returns a promise to supply the value at some point in the
future.
A Promise is in one of these states:
pending: initial state, neither fulfilled nor rejected.
fulfilled: meaning that the operation was completed successfully.
rejected: meaning that the operation failed.
A promise-based client returns promises rather than accepting callbacks.
Related
I've been using hooks in my React project for a while now and have developed a hook for getting data, similar to many others, which I use like this.
const [callApi, isLoading, result, errrors] = useData();
callApi is a function which you call with your data and axios config, it makes the API call and updates the other variables. I deal with the result in a useEffect() call which sets the state when it receives new data. It's fairly simple.
The problem is that while it works very well for one request at a time, it has a single isLoading state and a single result state, which is no good if it's called before the previous call is finished. Let's say my user sending a message to his friends and the UI shows a list of friends with a "send message" button next to each name, they might click 3 buttons and make 3 calls in quick succession. We then have a race condition to see which one sets the result first.
I'm used to imperative programming with promises, in my old Angular code the button click would call an event handler which would call the api and the promise .then() would then deal with the result. This could happen 100 times simultaneously and each one would resolve seperately and then update the UI.
So my question is, is there an idiomatic way of doing this declaratively using react hooks so that I can fire off multiple requests and deal with the loading/result/errors separately?
UPDATE
After some digging, it appears that the spied upon method in my effects layer (SheetEffects.clearAll) is not actually being mocked which is why the expect fails and so this isn't an issue w/ RTL.
ORIGINAL POST
I don't think I'm thinking about this incorrectly, but please give a thorough and well-thought reply if you disagree. KCD's react-testing-library documentation provides examples for asynchronously waiting for DOM to update before executing a Jest expect. My issue has to do with what if there is not a UI update during a similarly asynchronous process (and this may be beyond the intended scope of RTL)?
Given:
it('should dispatch the correct action when clicked', async () => {
const { container } = renderWithReduxProvider(<ClearAllButton />, {}, true)
// spying on this and checking if it's been called in the `wait` block fails
// jest.spyOn(SheetEffects, 'clearAll')
// this works within `wait`, but I don't need/want to test this here
const spy = jest.spyOn(SheetApiV2, 'clearAll').mockReturnValue(Promise.resolve())
fireEvent.click(container.firstChild as HTMLElement)
// this works, but I'm fairly certain it's a race condition
// and I'm just getting lucky
await wait(() => expect(spy).toHaveBeenCalledTimes(1))
})
Since I already have unit tests for the effects layer, I really just want to be able to specifically confirm that the component dispatched the correct action (via mapDispatchToProps). There are other side-effect ways to see that this has been done but I want to specifically test that the component dispatched the correct action and not that a reducer was invoked as a result of this action, or that an effect was called.
NB The renderWithReduxProvider function creates a Redux store with our effects middleware, and returns a <Provider/> wrapped connected component. Also note that effect functions are asynchronous.
I think the way you do it is correct, just wait for the method to be called.
However, I don't think I agree with this statement
Since I already have unit tests for the effects layer, I really just want to be able to specifically confirm that the component dispatched the correct action
In my opinion, you should test that the side effect happens. You see, calling SheetEffects.clearAll is an implementation detail. What if you decide to rewrite your app not to use Redux? Or what if you rename clearAll to clearEverything? In other words, what happens if you refactor the code? The test will break.
However, if you test the side effect, the test will still work because it does not care about the underlying implementation. The test will also give you much more confidence because you're going to test that the full feature works.
As a plus, you can get rid of the unit test for clearAll because you're implicitly testing it.
A little side note: when you use jest.spyOn you should reset your spy at the end of the test. You can do that with spy.mockRestore()
So the issue here is not RTL, but rather how spies work (in general, I believe, but feel free to correct with a well-thought reply). When a spy is created, it replaces the function being spied upon. I believe the issue in this case is 1) that the effect functions are registered long before the spy is created and how the effects middleware registers and invokes the effect function. By the time the latter occurs, it's not the spy that's invoked, but rather the original function.
I need to test out some different ways to inject logic into the effects middleware to allow for spying in tests.
For ease in explaining the significance of 'then', could anyone tell me what is happening in this code?
fetchComments().then(response => {
this.setState({
comments: response.comments
});
});
fetchComments returns a promise (probably; it could just be a "thenable"*). A promise is something that will be either resolved or rejected at a later point in time (typically**). then is used to hook up a handler that will be called when the promise is resolved (and optionally when it's rejected, if you pass a second function into then; otherwise you'd use catch).
In this case, that code says that when/if the promise returned by fetchComments resolves, use the resolution value to set the state of the React component using the comments property of that resolution value.
More about promises in this MDN article and in the Promises/A+ spec.
* See the Promises/A+ spec for what a "thenable" is.
** If you use then on a promise that's already resolved or rejected, you're guaranteed by the native promises in JavaScript that your handler will still be called asynchronously. That wasn't always the case with some early promise-like implementations, which would either call your callback asynchronously (if the promise wasn't already settled) or synchronously (if it was), which was...chaotic and unhelpful. JavaScript's native promises and any really good promise library guarantees consistent callback behavior.
I am answering this question bit late but may be helpful to someone at some time.
Let's Start:
From the above code you pasted, I can give you a hint that whenever you see a keyword then in any Javascript code snippet, that is an asynchronous function using promise.
Promise: are objects which store information about whether or not those events have happened yet, and if they have, what their outcome is.Usually, promise will handle success (a.k.a resolve in js code) and failure(a.k.a reject in js code) and also both. So when we create any async functions, the promise is created inside these async functions.
Promise.then: then allows us to assign event handlers to a promise. Depending on the arguments we supply, we can handle success, failure, or both and the return of then is also a promise which means it can handle more events.
And finally to get to the code above, fetchComments is a promise which is an async function, and when the response is resolve it is updating the state of the comments and additionally here we can also handle error scenarios using .catch or even by adding another then
and to end, below link has a nice explanation:
A nice tutorial on Promise and then in javascript is here
Function fetchComments 'll fetch Data and return one Promise then give them to state comments :). But I think you should read here^^.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Can anyone explain to me Observables? They keep referring to observables as like promises. If I can call a method and return data, why do I need an observable?
Angular is non blocking having promises/Observables allows your code to continue to run while the data you have requested is retrieved.
Promises sugar coat the callback pattern, do this then that then other. A Promise will act on data and either return a value or an error.
Since the creation of JavaScript, event listeners have been listening to and reacting to events in the browser. Observables are the latest and greatest abstraction of the observer pattern. It doesn't matter what the data source is, you can wrap an Observable around it.
When you are dealing with a stream of data, a Promise isn't of any use to you because the stream may not end, Observables solve the problem. Angular 2 uses Observables instead of Promises for dealing with HTTP.
beside success, error and then, do $http get rest promise offer more states we can act upon ?
I once logged in the console a raw response that showed these 3 states and more, but don't remember which.
the $http service extends on the $q service. The $http has 2 additional methods (success, and error) on top of the existing methods provided by $q (given below):
.then(successCallback, errorCallback, notifyCallback) – regardless of when the promise was or will be resolved or rejected, then calls one of the success or error callbacks asynchronously as soon as the result is available. The callbacks are called with a single argument: the result or rejection reason. Additionally, the notify callback may be called zero or more times to provide a progress indication, before the promise is resolved or rejected.
This method returns a new promise which is resolved or rejected via the return value of the successCallback, errorCallback. It also notifies via the return value of the notifyCallback method. The promise can not be resolved or rejected from the notifyCallback method.
.catch(errorCallback) – shorthand for promise.then(null, errorCallback)
.finally(callback) – allows you to observe either the fulfillment or rejection of a promise, but to do so without modifying the final value. This is useful to release resources or do some clean-up that needs to be done whether the promise was rejected or resolved. See the full specification for more information.