I'm working on a Stencil JS project, that makes some network calls to get data and update state.
In React JS, a network call would be done in componentDidMount lifecycle method, and not in componentWillMount method.
I'm surprised to find almost the opposite recommendation in the Stencil docs:
componentWillLoad() Called once just after the component is first connected to the DOM. Since this method is only called once, it's a
good place to load data asynchronously.
Stencil favors componentWillLoad over componentDidLoad in another case too. It logs out console warnings when using componentDidLoad to update state:
STENCIL: The state/prop "exampleProp" changed during "componentDidLoad()", this triggers extra re-renders, try to setup on
"componentWillLoad()"
Why does Stencil push users to componentWillLoad method (before render), while React pushes users to componentDidMount method (after render)?
To start off I don't know much about React but I saw that componentWillMount was deprecated with the following explanation.
There is a common misconception that fetching in componentWillMount lets you avoid the first empty rendering state. In practice this was never true because React has always executed render immediately after componentWillMount. If the data is not available by the time componentWillMount fires, the first render will still show a loading state regardless of where you initiate the fetch. This is why moving the fetch to componentDidMount has no perceptible effect in the vast majority of cases.
In Stencil you can return a Promise in componentWillLoad which will prevent the component from rendering until that Promise has resolved (but I never found a practical use-case for this).
If you don't return a Promise then depending on the speed of the your render method (any possibly other render lifecycle methods) componentDidLoad will run slightly later, which will probably be minimal most of the time (i.e. "no perceptible effect") but without any advantage (that I can think of).
componentDidLoad is meant for things that have to run right after the first render.
Similarly the console warning is because most of the time it doesn't make sense to synchronously modify a #State() or #Prop() property in componentDidLoad as it can often be easily moved to an earlier lifecycle method (avoiding a re-render just after the initial render). There are exceptions though, e.g. if the state value depends on the generated DOM, in that case you can ignore the warning.
Note that in some cases connectedCallback might be even more appropriate than componentWillLoad e.g. the clock example in Stencil's Life Cycle Methods docs.
Related
I am yet to work on static getDerivedStateFromProps so I am trying to understand about it.
I understand React has deprecated componentWillReceiveProps in React v16+ by introducing a new life cycle method called static getDerivedStateFromProps(). Ok but wondering why React has changed to a static method instead of a normal method.
Why
static getDerivedStateFromProps(nextProps, prevState){
}
Why not
getDerivedStateFromProps(nextProps, prevState){
}
I am unable to understand why it’s a static method.
To understand what React is trying to achieve with static methods, you should have a good understanding of the following:
Side-effects
Why is asynchronous code considered a bad approach up until the componentDidMount hook
Asynchronous rendering
How static methods aid in discouraging impure and asynchronous coding
Side-effect is nothing but manipulating any data out of scope. So side-effects in getDerivedStateFromProps would mean changes to any other variable other than its own local variables.
Functions that don't cause side-effects are called pure functions and in the case of their arguments, these are cloned before they are manipulated, thereby preserving the state of the objects that such arguments point to.
These functions simply return modified values from within their scope and the caller can decide the course of action with the returned data.
Inducing custom asynchronous code in a library like React with its own lifecycle flows is not a great idea. It should be carefully inserted at the right moment. Let's understand why by analysing the component creation lifecycle of a custom class component (to keep this short lets consider it is also the root element).
At the beginning the ReactDOM.render method invokes the react.createElement() method call.
react.createElement() => calls new ClassElement(props) constructor => returns the ClassElement instance.
After the constructor call, react.createElement() calls the ClassElement.getDerivedStateFromProps(props) method call.
After the above method returns, react.createElement() calls the instance.render() method.
(this can be skipped)
This is followed up with other synchronous calls such as diffing with
virtual DOM and updating real DOM etc and there are no hooks provided
to tap into these calls(mostly because there is no strong need). A key
point to note here is that javascript execution, real DOM updates and
UI painting - all - happen within a single thread in the browser thus
forcing them to be synchronous. This is one reason why you can write
something synchronous like:
let myDiv = document.getElementbyID("myDiv");
myDiv.style.width = "300px"; // myDiv already holds a reference to the real DOM element
console.log(myDiv.style.width); // the width is already set!
because you know at the end of each of those statements, that the
earlier statement is completed in DOM and in browser window(UI I
mean).
Finally, after the render method returns, react.createElement() calls the componentDidMount to successfully mark the end of lifecycle. Since it's the end, componentDidMount naturally serves as the best junction to attach asynchronous as well as impure functions.
What we must understand is that the lifecycle methods is constantly tweaked for performance and flexibility reasons and is completely under the control of React engineers. It's not just with React, in fact it's with any third party code's flow. So inducing impure functions or asynchronous calls could lead to issues because you would be forcing the React Engineers to be careful with their optimisations.
For e.g. if the React Engineers decide to run getDerivedStateFromProps twice or more times in a single lifecycle flow, both impure functions and asynchronous calls would be fired twice or more, directly affecting some part of the application. However with pure functions this would not be a problem because they only return values and it is upto the React Engineers to decide the course in the multiple getDerivedStateFromProps calls(they can simply discard all the returned values up until the last call and make use of the last one).
Yet another example would be what if the React Engineers decide to make the render call asynchronous. Maybe they would want to club all the render calls (from the parent to all the nested children) and fire them at once asynchronously to improve performance.
Now this would mean that the asynchronous calls written in render method or prior to it(like in constructor or getDerivedStateFromProps) could interfere with the render process because of the unpredictability in the asynchronous process completion. One could complete before or later than the other, triggering their respective callbacks unpredictably. This unpredictability could reflect in the form of multiple rendering, unpredictable state etc.
Importantly, both these ideas aren't just examples, rather were expressed by the React engineers as a possible future optimisation approach. read here: https://stackoverflow.com/a/41612993/923372
In spite of all this, React Engineers know the developers out there could still write asynchronous code or impure functions and to discourage that, they made one of the lifecycle methods static. The constructor, render, getSnapshotBeforeUpdate, componentDidMount and componentDidUpdate methods cant be static because they need to have access to instance properties like this.state, this.props, other custom event handlers etc.(constructor initialises them, render uses them to control the UI logic, other lifecycle methods need these to compare it with earlier states)
However considering getDerivedStateFromProps, this hook is only provided to return an updated clone of the state if the previous props is different from the current props. And by that very definition, this sounds pure with no need for any access to instance properties. Let's analyse why.
For this hook to work, the developer first needs to store the previous props in the instance state(let's say, in the constructor call). This is so because getDerivedStateFromProps receives the instance state as well as new props as arguments. The developer can then proceed to diff the desired property and return an updated clone of the state (without having the need to access this.props or this.state).
By making getDerivedStateFromProps static, not only is React forcing you to write pure functions, it is also making it difficult to write asynchronous calls because you have access to no instance from within this method. Usually the asynchronous call would provide a callback which would most probably be an instance method.
Now this doesn't mean the developers cant write them, instead this is just making it difficult and forcing to keep away from such approaches.
A simple rule of thumb is to stay away from impure and asynchronous functional approaches for the duration of third party induced flows. You should only induce such approaches at the end of such flows.
According to the description of this Proposal:
This proposal is intended to reduce the risk of writing
async-compatible React components.
It does this by removing many <sup>1</sup> of the potential pitfalls in
the current API while retaining important functionality the API
enables. I believe this can be accomplished through a combination of:
Choosing lifecycle method names that have a clearer, more limited purpose.
Making certain lifecycles static to prevent unsafe access of instance properties.
And here
Replace error-prone render phase lifecycle hooks with static methods
to make it easier to write async-compatible React components.
Eventually, after lots of discussions, the goal of using static method is also described officially here:
The goal of this proposal is to reduce the risk of writing
async-compatible React components. I believe that can be accomplished
by removing many1 of the potential pitfalls in the current API while
retaining important functionality the API enables. This can be done
through a combination of:
Choosing lifecycle method names that have a clearer, more limited purpose.
Making certain lifecycles static to prevent unsafe access of instance properties.
It is not possible to detect or prevent all side-effects (eg mutations
of global/shared objects).
You are not supposed to touch any internal data in that method so it is defined as static. This way there is no object you can touch and the only things you’re allowed to do are to use the provided previous state and next props to do whatever you’re doing.
getDerivedStateFromProps exists only to enable a component to update its internal state as a result of changes in props. As we update only state on the bases of props, so there is no reason of comparing nextProps and this.props. Here we should compare only next props and previous state, If state and props are different, update state otherwise there should be no update.
If we compare this.props with next props,we require to store the old props value, which impact performance. Keeping copy of past value is called memoization. To avoid misuse of “this” and memoization, getDerivedStateFromProps is made static.
We can consider above as the reason for componentWillReciveProps depreciation too.
getDerivedStateFromProps is a new API that has been introduced in order for it to be extensible when Async rendering as a feature is released. According to Dan Abramov in a tweet,
This method is chosen to be static to help ensure purity which is
important because it fires during interruptible phase.
The idea to move all unstable things and side effects after the render method. Giving access to component instance variables during an interruptible phase may lead to people using it with all sorts of side effects causing an inconsistency in async rendering
Firing server call to fetch data in componentWillMount life cycle method a bad practice?
And why it is better to use componentDidMount.
UPDATE: componentWillMount will soon be deprecated.
To cite #Dan Abramov
In future versions of React we expect that componentWillMount will fire more than once in some cases, so you should use componentDidMount for network requests.
Read more here.
UPDATE - may / 2018
There is a new feature for react in a working progress called async rendering.
As of react v16.3.2 these methods are not "safe" to use:
componentWillMount
componentWillReceiveProps
componentWillUpdate
you can read more about it in the docs.
As a general rule don't use componentWillMount at all (if you use the es6 class syntax). use the constructor method instead.
This life-cycle method is good for a sync state initialization.
componentDidMount in the other hand is good for async state manipulation.
Why?
Well, when you do an async request in the constructor / componentWillMount you do it before render gets called, by the time the async operation has finished the render method most probably already finished and no point to set the "initial state" at this stage is it?.
I'm not sure this is your case here, but most of the cases that developers wants to initiate state asynchronously in componentWillMount is to avoid a second render call. but you can't avoid it can you, like mentioned above, render will fire anyway before the async operation will finish.
So, the best time to call an async operation is after a render has called and the component mounted (you could mount null or an empty <div/>) and then fetch your data, set the state and make it re-render respectively.
componentDidMount is the best place to put calls to fetch data, for two reasons:
Using componentDidMount makes it clear that data won’t be loaded until after the initial render. You need to setup initial state properly, so you don’t get undefined state that causes errors.
If you need to render your app on the server, componentWillMount will be called twice(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. Generally, you should not add side effects to componentWillMount.
Component Mounting life cycle is
constructor()
componentWillMount() /UNSAFE_componentWillMount()(react 16)
render()
componentDidMount()
Constructor and componentWillMount both call before render() call which is responsible for page rendering.
Here State initialized is done in Constructor and api are called in componentDidMount because of async calls.
ComponentWillMount was good to initialized state before ES6 when constructor was not there. But now ComponentWillMount is good for nothing and react team is thinking it after react 17.
In addition to above, react have moved to react fiber architecture, to avoid unnecessary re-rendering and improve performance, react has decided to move away from componentWillMount, componentWillReciveProps and componentWillUpdate methods.
The way I understand it, one of the biggest reasons has to do with setting up the right expectations for the developers reading the code.
If we use componentWillMount it's tempting to think that the fetch have time to happen, then the component "did" mount, and then the first render will happen. But that it not the case. If we do an async call (like an API call with Promises), the component will actually run render before the fetch can return and set the component state (or change the Redux state, or what ever).
If we instead use componentDidMount, then it's clear that the component will render at least once before you get back any data (because the component already did mount). So, by extension, it's also clear that we have to handle the initial state in a way so that the component doesn't break on the first ("empty") render.
I'd like to run a function upon receiving props initially and upon any subsequent props changes. Consequently, I was planning on checking props and running this function in both componentDidMount and componentWillReceiveProps. However, this seems redundant. I've seen people also check props and run functions inside render(), but I was under the impression this was frowned upon.
What should be my solution here?
There is no substitute to catch both componentDidMount and componentWillReceiveProps in a single callback. The best way to do this is to define a function and call it from both of these callbacks.
I was planning on checking props and running this function
Is a very vague description of what you're trying to do. Just checking the props alone doesn't seem to be problematic if done inside the render function. But it would become a problem if this part is causing side effects which (can) in turn trigger a component re-render. If this is the case, I'd say "frowned upon" is putting it lightly. The problem with this is that your render function is adding side effects which are in turn triggering more re-renders and on it goes. It will instantly kill the performance of your app and could even make the whole thing grind to a halt.
Your question is tagged with both React and Redux. Are you using a mapStateToProps function that you use with connect?
If so, a possible answer could be to dispatch this action (or run this function) in the mapStateToProps function, since this will be run both initially, and then every time you update the redux state. You'd have to make sure the action/function doesn't cause yet another state change though, so that you end up in a loop.
Edit: #DuncanThacker pointed out this might not be a good idea, because mapStateToProps may fire very often, resulting in performance issues. Good point.
As per this link https://facebook.github.io/react/tips/initial-ajax.html,
I've built a todo app that works great. I fetch my data in componentDidMount hook like they say to. I just had a question on the why.
Why do we fetch data after the components mounted? Seems to me it just ends up re-rendering once the data gets set in setState() in the hook.
Why not just fetch the data in constructor() and set the initial state with data? Wouldn't that be just the 1 render? Seems less expensive even if its only partially re-rendering because of the virtual DOM.
The fetch will generally be executing asynchronously so it's always going to cause a second render despite it being within componentWillMount or componentDidMount.
I believe they are recommending to put it within the componentDidMount as you may be using a browser dependant implementation of sorts. When executing/rendering components on the server (i.e. within node) only componentWillMount gets executed, and therefore could fall over if you are using a browser/DOM dependant feature. The other lifecyle methods (i.e. componentDidMount) don't get executed on the server, so hence the safety and recommendation I think. Although in general I have found it more useful when needing to do DOM access. Use a universal ajax library (i.e. runs on node/browser) and this probably won't be a concern for you.
I saw this line as an answer to another question on here:
"componentWillMount should be componentDidMount, or else you'll leak event emitters in node."
and I don't really understand it. Can someone explain with more detail?
More info:
Building a react application with flux, as part of the initial render, a child component computes some data. Ideally, after this data is computed, I would like to call an action that updates the store's state with a portion of this new data.
Normally, updating the store's state emits a change event that causes a re-render. However, because the change listener isn't being added until componentDidMount (rather than in componentWillMount), my top level component isn't able to listen for the change that occurs during the initial render and initiate a re-render.
If I move the addChangeListener to componentWillMount that would seem to fix this issue, but the above quote suggests that this is a bad idea?
I think the prevailing wisdom that listeners should be set in componentDidMount because it prevents problems in isomorphic applications is a mistake. I think in 98% of cases for non-isomorphic applications setting listeners in either componentWillMount and componentDidMount will work the same way, but it is conceptually wrong and in the 2% of cases (such as the example given in the original question) it will do the wrong thing.
There are git issue discussions and comments in the React source code suggesting that it would be preferred that componentWillMount wasn't called on the server at all, but if it isn't then problems are created in the checksum test comparing the server prerender to the client initial render. Having componentWillMount on the server means that it isn't executed as part of the component lifecycle in this case, but this is being used as an excuse to not count it as part of the lifecycle in any case.
In fact, componentWillMount is exactly the right place to register listeners if you are not creating an isomorphic application. If you are creating an isomorphic application then you have to make some compromises due to the checksum/lifecycle issue not being ideal in this case (maybe just testing for the server environment and then not registering listeners?).
In non-isomorphic applications adding listeners in componentWillMount can save unnecessary re-renders in some cases and will register them in document order. The advantage of document order is that if you have a way to flush pending events as components are re-rendered (for example, takeRecords on a MutationObserver) then you can ensure the document is re-rendered top down instead of bottom up, converting the rendering complexity to linear from polynomial.
Additionally, there is no danger period between the initial render and when the listener is registered where the Store can change without triggering a render, causing the view to be out of sync with the Store (the example problem given in the original question). If the listener is registered in componentDidMount you either need to make sure the Store isn't changed in componentDidMount calls in children, or else force a re-render/re-sync after registering the listener, which if done in componentDidMount is done in reverse document order which may be polynomial complexity (depending on how/if the React setStates are aggregated).
Is hard to understand what that quote means without more context. What I can tell you is that there are huge differences between the two of those methods.
On one hand, componentWillMount is called before the component is actually added to the DOM. This is the last chance you have to update component's state and get it rendered before the component is rendered by the browser.
On the other hand, componentDidMount is called once the component has been attached to the DOM (the real one).
What you need really depends on your use case. In general, componentDidMount is used to integrate with other libraries (like jQuery), it provides a way to modify the HTML rendered by the component.
I suggest you to read these links:
https://facebook.github.io/react/docs/component-specs.html#mounting-componentwillmount
https://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount
https://facebook.github.io/react/tips/use-react-with-other-libraries.html