Why are browser api event subscribed to in componentDidMount in React? - reactjs

In this talk https://reactjs.org/docs/hooks-intro.html the speaker write codes that resemble this :
class SomeComponent extends React.Component {
constructor(props){
super(props)
this.handleResize.bind(this)
}
handleResize(){
//do something with window.innerWidth
}
componentDidMount(){
window.addEventListener('resize',this.handleResize)
}
}
Why is the window.addEventListener part in componentDidMount ? Does it have to be ?
From the tone of the talk, I felt that this situation was pretty common.
I'm fairly new to react, and I would have put the browser api event subscription in the constructor just as well.
Is there any advantage that would have elude be as to why put this window.addEventListener in componentDidMount ? Or is it juste for readability purposes ?

To me it's quite simple.
First, you only want api call or event listeners to be called/initialised only once, componentDidMount() and constructor is guaranteed to run only once per mounted component.
However, I won't put api in constructor because if you want a UI update after your data is returned from the api, you need a state change, while you cannot set state in constructor. The only place that only run once and allow you to setState is componentDidMount().
For Event listeners I think it can be put in constructor/componentDidMount. However, the official docs do recommend that to be put in componentDidMount(). Have a look at this.
componentDidMount is called after the component is mounted and has a DOM representation. This is often a place where you would attach generic DOM events.

In general, constructors must not have any side effects.
And also React documentation already mentioned this:
Avoid introducing any side-effects or subscriptions in the constructor. For those use cases, use componentDidMount() instead.

The window.addEventListener define in the componentDidMount life cycle, because code defined inside componentDidMount is executed after the DOM have been rendered. And that would be the right moment to try to attach any event handler to element which is part of the DOM.
But if you did so inside constructor, there are many chance for that to be called before the DOM had been rendered completely.
Read more here

There are multiple reasons about componentDidMount()
In practice, componentDidMount is the best place to put calls to fetch data, for multiple reasons.
1- If you want to subscribe and unsubscribe your function then you need to call that function in componentDidMount() and to unsubscribe(after all operation) call in componentWillUnmount()
2-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.
3-componentDidMount() lifecycle method is called after render() to make sure successful DOM loading.
window.addEventListener('resize',this.handleResize)=>
You can call in constructor as well but later if you need to
unsubscribe, can't do because it's initial phase(called initially
only).

Related

Is setState() inside componentDidMount() considered an anti-pattern

I've just had a look at this discussion about setState() inside componentDidMount().
You can see that after the render() function, the componentDidMount() function will be called by React. When you put a setState() call in componentDidMount() then you are causing the entire component tree be re-rendered not only the current component - not to forget, the current component did just finished with rendering.
And some people suggested to put setState() call inside componentWillMount(). In some cases, I want to get the height of a rendered element and store it as state, and the above method wouldn't work. I also had a look at the React official website, and it suggests to do Ajax call inside componentDidMount(), which again goes against the above idea.
So, am I wrong about putting setState() inside componentDidMount()? If yes, what should I apply as an alternative?
You may call setState() immediately in componentDidMount(). It will
trigger an extra rendering, but it will happen before the browser
updates the screen. This guarantees that even though the render() will
be called twice in this case, the user won’t see the intermediate
state. Use this pattern with caution because it often causes
performance issues. In most cases, you should be able to assign the
initial state in the constructor() instead. It can, however, be
necessary for cases like modals and tooltips when you need to measure
a DOM node before rendering something that depends on its size or
position.
React docs
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.
Example
TLDR:
- If you have all needed data in constructor - assign state there
constructor(props) {
super(props);
// Don't call this.setState() here!
this.state = { counter: 0 };
}
Call async action, touch DOM in componentDidMount()
Your case with unknowing the height of a rendered element might be a valid excuse to use setState inside componentDidMount. However in such a case I would definitely add another lifecycle method,shouldComponentUpdate, to control the rerender issue.
Normally you don't want to do synchronous state setting inside componentDidMount, you should just put it in the constructor. However element height is a bit unique, since you can't actually get the height of an element until it's mounted and rendered into the DOM.
So normally not, but in the case of element height it's ok to do it in componentDidMount.
You can do Async call and you must do it inside the componentDidMount() lifecycle hook. But this will call the render method again.
If you don't want the re-render to happen again, use the shouldComponentUpdate() method to prevent re-rendering the DOM. Example as follows:
shouldComponentUpdate (nextProps, nextState) {
// check the condition here
if (nextState.something !== 'value') {
// stop re-rendering
return false;
}
// continue rendering
return true;
}

which is the right place to call the actions, componentWillMount() or componentDidMount()?

componentWillMount() called before dom is rendered. shall I call my action from here or from componentDidMount()?
What is the difference and which one should i prefer?
componentWillMount is called before mounting, therefore if your action changes state 'synchronously' this action will not lead to a re-rendering. This would be one of the big differences. The docs suggest you use the constructor instead of this method to initialise your comp.
actions from inside componentDidMount() will lead to re-render which might get expensive if the action changes state for an upstream component (if they are stateful) network calls should be handled at this stage typically.
The plan is to deprecate componentWillMount() in React 17, so I wouldn't use that in new code.

Where to check property availability on window in React lifecycle?

I would like to have an information about Device Orientation API support in one of my React Components. That's why I would like to have something like this (see code below) somewhere in the component lifecycle:
this.state = {
isDeviceMotionSupported: 'ondevicemotion' in window,
}
I'm not sure if I reason correctly, but here is what I think:
constructor, componentWillMount won't be a good places as I'm using server side rendering.
componentDidMount won't be a good place because setting state in this method will trigger a re-rendering.
componentWillReceiveProps, shouldComponentUpdate, componentWillUpdate, componentDidUpdate won't be a good place as they will be called many times, so we having this check there if I only need to do it once
Where would be the best place to put such check and why?

Set state after component did mount?

A story:
I have a server rendering but some part of my app cannot be done there, since they use document(react-art library for drawing on a canvas).
I cannot render everything in the same from, because react will say that the code received from a server and and client one are not the same.
So my solution is to render some part of my app on the server, then render this part on a client and, in the next frame, render everything that is impossible to render on a client.
So I was thinking about using setState in componentDidMount and trigger DOM update, so it can contain rendered client part which cannot be rendered on a server, but eslint says it is not good to set state in componentDidMount. Logically I cannot say why it is bad in this case. Generally it is not good because it triggers DOM update, but in my case, this is what I actually need.
What would you suggested in this case?
Edit 1:
Fixed typo, I mean componentDidMount not componentDidUpdate.
Edit 2:
Here is the same issue, but they use changing state in componentDidMount as a workaround.
I've just coded a similar scenario and happily used componentDidMount disabling ESLint's warning. IMHO it is perfectly valid ONLY in universal rendering scenarios.
Why: Using setState in discouraged in componentDidMount because you'll trigger an additional, unnecessary render.
However in a universal scenario where you want to differ server and client behaviour, you'll want that additional render and in order to prevent 'could not reuse markup' errors, you'll want it just after react reconciles with the server rendered DOM. In brief: You'll render twice in any case.
I don't however recommend coding this behaviour in a leaf / dumb component because doing so would require the supposedly dumb component to have some knowledge of it's environment (client / server) and present a design problem. Creating a component that would set the props of the dumb component would be the obvious solution.
Try setting state in componentWillMount or componentWillUpdate.
Be careful with componentWillMount, it can also be called server side.
What i understand from your question is that after your component is mounted, data on server and client changes and you want to keep component in sync with changing data.
I recommend you have a look at the flux or redux architectures of react. For example flux is implemented in a way that when anything in component changes it triggers action and listens to the store. And when anything in store is changed then component will re render itself.
Please see this link About ReactJS - Component Life Cycle.
you should use from componentWillMount cycle. componentWillMount is executed before rendering, on both server and client side.
I want to know how to trigger components update after my app is mounted.
In React, the conventional way to "push" state onto a component is using props, not state. If your application needs to acquire information client-side and adjust component state accordingly, you should implement componentWillReceiveProps.
If you feel that the state rendered on the server and in-browser are of the same kind, and don't want the hassle of tracking which properties belong this.state v. this.props, I suggest something like the following:
componentWillReceiveProps(nextProps) {
this.setState( Object.assign({}, this.state, nextProps) );
}
This will merge the passed properties into the component state, so that they can be accessed using this.state.
Prevent usage of setState in componentDidMount.
Updating the state after a component mount will trigger a second render() call and can lead to property/layout thrashing.
The following patterns are considered warnings:
class MyComponent extends React.Component {
componentDidMount(){
this.setState({
data: data
});
}
}
The following patterns are not considered warnings:
class MyComponent extends React.Component {
constructor(){
this.setState({
data: data
});
}
componentDidMount(){
...
}
}

more information on React lifecycle methods

I'm actually working on React and I want to consolidate my knowledge on it.
Starting with lifecycle methods:
getDefaultProps:
properties from both getDefaultProps and parent are consolidate here in this.props like that properties now are ready to be consumed by "getInitialState"
getInitialState:
this.props are used to set the state of the component. The component is now ready to be render
componentWillMount:
what can we do inside ?
render:
self explain
componentWillMount:
we can do some actions to clean the component
componentWillMount seems overkill ?
What do you think ?
My answer assumes your bullet after render was meant to be componentDidMount.
The big difference between the two
componentWillMount is called before the component renders. Anything that needs to be done before rendering should exist in this function (initial calls to retrieve data, initialization of internal structures, etc.).
componentDidMount is called after the component has rendered. Since the component is now added to the DOM tree, any additional DOM manipulation can be performed. Perhaps fire off events notifying the rest of the app that the component is rendered or add the element into a non-React DOM tree.
State modification in componentWillMount will not cause additional rendering, so, it is a place for additional state initialization based on passed props. This article describes lifecycle methods: https://facebook.github.io/react/docs/component-specs.html
P.S. And one more article on state initialization, that could be useful, since you mentioned initializing state from props: https://facebook.github.io/react/tips/props-in-getInitialState-as-anti-pattern.html

Resources