React componentWillUpdate getting called twice - javascript

Iam new to React and i came across with this doc. It says that:
Either way, it is unsafe to use componentWillUpdate for this purpose
in async mode, because the external callback might get called multiple
times for a single update
How is it possible for the componentWillUpdate to be called multiple times? It doesnt explain it.
Thank you

Any change that is supposed to trigger a render will first go through a componentWillUpdate lifecycle. The change change can be a parent re-render causing the child to re-render, a change in components props, or a change in state.
However from v16.3.0 this lifecycle method is deprecated and it is encouraged that any sideeffect be handled in componentDidUpdate which will be triggered after render method.

On async mode, your component update/render may be postponed so react can deliver some hi-priority stuff. This means willUpdate will be called each time react starts working on your component, but it might not finish the full update, hence calling willUpdate every time it starts working on this component but only calls didUpdate once, after this process is finished.

Related

Does React 18 batch render after state updates inside lifecycle methods

Since React 18 introduced batch rendering in all places, we've been facing issues in our application. In our application, re-render needs to happen right away rather than batching. So we used flushSync() for every setState() call. Now we face an error/warning in the console "flushSync was called from inside a lifecycle method. React cannot flush them when React is already rendering. Consider moving this call to a scheduler task of the microtask". Is there any way we can use multiple setStates inside a handler and not have them batched?

Where to make API hits ComonentDidMount or in ComonentDidUpdate [React.JS]

In an interview, an interviewer asked me that where should you make API-hits in a simple react application? Meaning in which life-cycle method in a Class-Component. I knew the answer to be ComponentDidMount - because it is the first life-cycle method where we get complete rendered dom meaning dom is now ready!
Then he asked, but why NOT in comonentDidUpdate?
Now, I told him what I had read somewhere, I don't know the exact answer of this -- except ComponentDidMount runs first, so make it there.
Now, can someone tell me if my answer was correct? Or should we make API-hits in ComponentDidUpdate()?
I am confused. Kindly, someone explain with reasoning? Thanks in Advance!
It depends on when you want to call the API:
If an API call is done only once then do componentDidMount
If after render based on some state, you want to fetch data again then do it in componentDidUpdate
EDIT:
Same scenarios can be handled within functional components using useEffect hook as follows:
1- Only runs the first time when the components render same as componentDidMount:
useEffect(() => {
// Run only once when the component renders
}, []); // Pass empty array as dependencies
2- Run every time when component renders either by props change or by local state change same as componentDidUpdate without comparing previous and current props:
useEffect(() => {
// Run every time the component re-renders including the first time
}); // Do NOT pass array dependencies
3- Run only when particular props change, same as componentDidUpdate but with props comparison:
useEffect(() => {
// Run only when the component prop1 and prop2 changes
}, [prop1, prop2]); // Pass props as array dependencies
Reference: Using the Effect Hook
Lets take an example scenario.
You have a profile page and it has a text box which allows you to update tags.
You do a fetch for the whole profile in the componentDidMount to get all the details and show the content.
And then componentDidUpdate will have to be used for something like the update on tags, lets say you do a fetch to get tags based on the user input for every 3 letters the user type. then you use componenDidUpdate to check the state and do the call.
If you think of the same in functional components we'll have to use useEffect.
useEffect(()=>{},[]);
See the array of dependecies, if you pass an empty array it would act similar to componentDidMount.
And the componentDidUpdate
useEffect(()=>{},[tagText]);
Here the effect will run only when a change it done to the tagText, but the componenDidUpdate would be different as you will have to compare the previous state and decide whether the text is updated.
According the Official React Documentation (Link):
componentDidMount
componentDidMount() is invoked immediately after a component is mounted (inserted into the tree). Initialization that requires DOM nodes should go here. If you need to load data from a remote endpoint, this is a good place to instantiate the network request.
This method is a good place to set up any subscriptions. If you do
that, don’t forget to unsubscribe in componentWillUnmount().
componentDidUpdate()
componentDidUpdate() is invoked immediately after updating occurs.
This method is not called for the initial render.
Use this as an opportunity to operate on the DOM when the component
has been updated. This is also a good place to do network requests as
long as you compare the current props to previous props (e.g. a
network request may not be necessary if the props have not changed).
Check out this link for a complete big picture. This will be handy while learning react.

ComponentWillMount can't find an variable

I have already created a react native CLI project. Now every time when user come to my screen I want to update some value. In my home screen, I have three top tabs. When the user clicks on the 3rd tab. I need to update some values every time.
For those three tabs, I am using: ScrollableTabView
import ScrollableTabView, { DefaultTabBar } from 'react-native-scrollable-tab-view';
I used this below code for every time to update the values. But this is calling only for one time:
useEffect(() => {
alert('i called');
})
Then i tried :
import React, { useEffect, Component } from 'react';
componentWillMount( () => {
alert('called ');
})
But I am getting error like cant the variable componentWillMount.
How can I solve? Please help.
Thanks.
It seems like you are using the new React Native way by using hooks and functional components only.
It is not possible to use reacts lifecycle methods anymore - you will have to write your own componentWillMount code. Take a look at the docs or take a look at this answer:
How to use componentWillMount() in React Hooks?
~Faded
So, going back to React basics. There are 2 ways of declaring a component: using a Class based component or using a functional component which you are clearly using.
Before React Hooks, we couldn't have state in our functional components, that means that you cannot use the LifeCycle Methods from a Class based Component. I really suggest you to read the documentation. Instead, we can use hooks to get the same behavior.
Now, the useEffect hook will receive 2 parameters: the first one is the callback we are going to execute, and the second is an array of dependencies that will trigger that hook. It means that the hook will watch for changes in the variables you put in your array. Since you are not declaring an array of dependencies, the hook will be executed on every render.
So, what's exactly the problem? The problem is that declaring your tabs with react-native-scrollable-tab-view won't unmount the components for each tab, there are no variations, that's because your alert log is only being logged once. Because there are no more renders, just once.
Looking at the docs, you might be using onChangeTab method, which apparently will be called when changing the tab.

Exactly when happense React state update on an unmounted component WARNING?

Exactly when should we check if a component mounted or not ???
I have a lot of setState call and I encounter some time with the warning I wrote in the title.
Now I can avoid this by declaring a variable and initializing to true in componentDidMount and re asigning to false on componentWillUnmount, and then check when setState gets call.
But My Exact question is, Is it necessary to check every time setState calls, or this warning happens in specific cicumstances ? and I should check the variable on that time ?
Also will affect this warning on performance?
It can happen when you call setState asynchronously, e.g. window.fetch().then(...setState...) or await or inside a callback.
You could use this.isMounted() instead of your custom variable, but see also https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html for better solutions.

Use componentWillMount or componentDidMount lifecycle functions for async request in React

I am reading up on react lifecycle and am getting a little confused. Some recommend using componentWillMount to make ajax calls:
https://hashnode.com/post/why-is-it-a-bad-idea-to-call-setstate-immediately-after-componentdidmount-in-react-cim5vz8kn01flek53aqa22mby
Calling setState in componentDidMount will trigger another render()
call and it can lead to layout thrashing.
and in other places it says not to put ajax calls in the componentWillMount:
https://medium.com/#baphemot/understanding-reactjs-component-life-cycle-823a640b3e8d
...this function might end up being called multiple times before the
initial render is called so might result in triggering multiple
side-effects. Due to this fact it is not recommended to use this
function for any side-effect causing operations.
Which is correct?
The React docs recommend on using componentDidMount for making network Requests
componentDidMount() is invoked immediately after a component is
mounted. Initialization that requires DOM nodes should go here. If you
need to load data from a remote endpoint, this is a good place to
instantiate the network request.
Calling setState() in this method will trigger an extra rendering, but
it is guaranteed to flush during the same tick. This guarantees that
even though the render() will be called twice in this case, the user
won’t see the intermediate state.
As per the case for componentWillMount:
EDIT:
This lifecycle is deprecated since v16.3.0 of react and is no longer encouraged for usage.However its renamed to UNSAFE_componentWillUpdate and is expected to work till at least v17 of react
Before v16.3.0
An asynchronous call to fetch data will not return before the render happens. This means the component will render with empty data at least once.
There is no way to “pause” rendering to wait for data to arrive. You cannot return a promise from componentWillMount or wrangle in a setTimeout somehow. The right way to handle this is to setup the component’s initial state so that it’s valid for rendering.
To Sum it up
In practice, componentDidMount is the best place to put calls to fetch data, for two reasons:
Using DidMount makes it clear that data won’t be loaded until after
the initial render. This reminds you to set up initial state
properly, so you don’t end up with undefined state that causes
errors.
If you ever need to render your app on the server, componentWillMount will actually be
called twice – once on the server, and again on the client – which is
probably not what you want. Putting the data loading code in
componentDidMount will ensure that data is only fetched from the
client.
componentDidMount is the recommended lifecycle method to make Ajax calls as described in their docs
ComponentDidMount is the place.
But if you have time try to look at Redux and make the requests in actions, as your application grow it will help a lot to manage the app state.
;)

Categories

Resources