How do I use async await when a component leaves view - reactjs

How do I use Async Await ?
When this.props.onChangeStep1() is called, the component where the view is rendered is replaced by another component.
If the component has been swapped would Async Await still work ?
s3.upload(params, function(err, data) {
this.props.onChangeStep1(); //<----- After s3.upload I want to call this first
this.setState( //<----But I want this to run in the background
// even though the component is not in view
{
myState: "data-from-s3Upload"
});
}.bind(this)
);

If a callback is set to be executed later and the component that initiated the asynchronous call is unmounted, the callback will be executed regardless. If the callback attempts to act on the unmounted component (changing its state for instance) it will be considered as a memory leak and React will notify you with an error message in the console.

this.props.onChangeStep1(e) // <-- Forward data and Process logic on App.js / Parent Component

Related

How does firebase's onAuthStateChanged work in ComponentDidMount lifecycle in reactJS

Can anyone explain we how this onAuthStateChanged function is working inside componentDidMount. I know this lifecycle hook get executed only once when the component is mounted. So how does the function inside gets executed?
What I assume is it's like callback function which keeps on running in event loop as gets fired when state changed like addEventlistner in JS.
componentDidMount() {
console.log("Context Mounted");
firebaseapp.auth().onAuthStateChanged((user) => {
if (user) {
this.setState({ currentUser: user });
console.log("User Signed IN ");
} else {
console.log("THERE IS NO USER");
}
});
}
You pretty much got the gist of it: after your register your onAuthStateChanged callback with Firebase it will be called:
"immediately" with the current authentication state
whenever that authentication state changes
Since you call setState to put the user into the state, this then triggers a rerender of the UI whenever one of the above events occurs.
This continues until the app exits or until your unregister the listener, which you should typically do in the componentWillUnmount method of the same component.

In Enzyme how to wait for an API call in the componentDidMount method?

We have a React component which we mount with Enzyme:
const component = mount(<App/>);
The component loads data on componentDidMount which we mock with nock:
nock('http://localhost:3100').get(`/api/data`).reply(200, DATA...);
We want to test the value of a label inside the component. However the value is only populated after the data is loaded via the fetch call. How can we wait for the fetch call to finish before writing the expect:
expect(...
You would have to do something like:
Promise
.resolve(mounted)
.then(() => mounted.update())
.then(() => {
expect(label === value); // Just using pseudocode here to denote where to write the expect statement
})
You might still face incorrect behavior here, in which case you can check this thread

How should I mock state in a functional stateful component with state hooks when testing?

If I have a stateful functional component that uses state hooks, how can I manipulate the state from outside the component? I want to be able change the state in my tests so that I can test how the dom changes.
I want to be able to change the value of something like this from outside of the component:
const [sent, setSent] = useState(false);
I would not test the internal state of the component but rather what this state might represent. The usage of the state is an implementation detail and you should test if the specification is implemented correctly and not how it is implemented.
In your case I would use the following approach:
Call the functionality that should set the sent state (button click,
form submit)
Test if the sent status is handled correctly in your
component (a success message is shown?)
Testing loading states of api calls can be achieved with mocks. If you don't use some fancy library but just do normal await apiCall() then you can use following approach:
Mock your api call (you probably already doing it)
Return a Promise() from the mock that will not be resolved
Example with enzyme:
import { apiCall } from '../api';
jest.mock('../api');
// ...
it('Contains a <Loading /> on loading', () => {
// The promise won't be resolved so the loading state will persist
apiCall.mockReturnValue(new Promise(() => null));
// await act... and wrapper.update() might not be needed
// depending on your implementation
await act(async () => {
wrapper.find(SubmitButton).simulate('click');
});
wrapper.update();
expect(wrapper.find(Loading)).toHaveLength(1);
});

Fetch data on Async ComponentDidMount before rendering

In my componentWillMount function, I have an async function getResults that fetches data from a server. I want to pass the response from getResults to the same component on initial load, but I noticed that my component renders before waiting for the data to come back from getResults. How do I make the component wait for the response before having it render? I am using Redux to handle my state.
async componentWillMount() {
const response = await getResults(this.props.category)
}
Async/Await only makes your code look synchronous.
async componentWillMount() {
const response = await getResults(this.props.category)
this.setState({
// use response to set your state.
});
}
Set state is what causes the re-render.
You then use the state to determine if you are in a loading state. If so it may be good to show the user. You also want to handle the default data in the first render. Once you retrieve your response you set the data to the second state.
It's idiomatic React to render your component asynchronously. You'll fetch your data, and set your state accordingly... with a new state, your component will re-render. A common practice it to render the component with a spinner, and when the state is set, re-render with the actual data. At the very least, you can render null until your async request completes and sets your state.
componentWillMount() is invoked just before mounting occurs. It is
called before render(), therefore calling setState() synchronously in
this method will not trigger an extra rendering. Generally, we
recommend using the constructor() instead.
Avoid introducing any side-effects or subscriptions in this method.
For those use cases, use componentDidMount() instead.
This is the only lifecycle hook called on server rendering.
source
You can use componentDidMount() and make the rendering conditional and waiting for the result from the API, and then render it with the result.

React componentDidMount() is fired on unMounted component

A simple react component that invokes a promise from the data store on componentDidMount is throwing a warning:
Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the LocationNameView component.
I threw a few debug console.log to see if this.isMounted() is true/false, and inside componentDidMount this.isMounted() will return false the first time then again and it will be true. I'm not sure if the docs are clear or the name of componentDidMount is skewing my reasoning here but it seems like this method should only be invoked if the component is actually mounted.
enter link description here
componentDidMount: function() {
var self = this;
// make the request to the backend and replace the loading location text
Models.Location.find(this.props.location)
.then(function(location) {
console.log(self.isMounted()); // <--- shows false then true
self.setState({ location : location });
});
},
componentDidMount is invoked when the underlying DOM representation is built, but, not yet mounted to the actual DOM.
The reason the warning is being displayed about setting state on an unMounted component is because the aSync callback in the above example can return before the component is actually mounted to the DOM tree in the client/browser.
The lesson here is if you're using an aSync callback that sets state in your component on componentWillMount or componentDidMount, first use the safety catch isMounted() before proceeding to setting state, ie:
componentDidMount() {
let self = this;
PromiseMethod().then(function aSyncCallback(data) {
if ( self.isMounted() ) {
self.setState({...data});
}
});
}
React Component Lifecycle reference

Resources