is componentDidMount rerender the component? - reactjs

At first my favorite color is red, but give me a second, and it is yellow instead.
will componentDidMount cause the component rerender to display color yellow?
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
componentDidMount() {
setTimeout(() => {
this.setState({favoritecolor: "yellow"})
}, 1000)
}
render() {
return (
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
);
}
}
ReactDOM.render(<Header />, document.getElementById('root'));

Taken from the React docs:
componentDidMount() is invoked immediately after a component is mounted (inserted into the tree).
so yes, but...
Also from the docs:
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.
That means you will only see the yellow color.

componentDidMount is a lifecycle method that is called only when the component is mounted. It is called only once after the first render.
componentDidMount() {
// Runs after the first render() lifecycle
}
When React looks at this code, it’s going to first render the component (the constructor() is the first method called) and you will see at first the color is red.
Right after that, React checks if the component has componentDidMount() method to run any side effects.
In your componentDidMount() method, you're telling React to update the state of the component.
So that, this.state.favoritecolor went from red to yellow.
Helpful Link: Understanding React componentDidMount and how it works

Related

Autocall any function in component where ever it is rendered

I'm new to React JS coding...
I would like to know any method to be called in Class-Based Components whenever it gets props and called by another component in their render return methods.
Actually! I wanted to run that function every time when that component is being Rendered or Called By another component.
I appreciate that...
In React class components, the render method itself shouldn’t cause side effects. It would be too early — we typically want to perform our effects after React has updated the DOM.
This is why in React classes, we put side effects into componentDidMount and componentDidUpdate. Coming back to our example, here is a React counter class component that updates the document title right after React makes changes to the DOM:
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
componentDidMount() {
document.title = `You clicked ${this.state.count} times`;
}
componentDidUpdate() {
document.title = `You clicked ${this.state.count} times`;
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
we have to duplicate the code between these two lifecycle methods in Classes.
This is because in many cases we want to perform the same side effect regardless of whether the component just mounted, or if it has been updated. Conceptually, we want it to happen after every render — but React class components don’t have a method like this. We could extract a separate method but we would still have to call it in two places.

Is that possible that a component will also be re-rendered without props and states changing

In React, if father component "A" re-rendered and change the position of its son component "B", but B's props and states aren't changed, then will the "B" be re-rendered? If it will, why is that necessary?
Below is code in parent component, and "Poker" is the child. "this.props.localPokers" is an array which can be added element by clicking a button:
the position of bottom poker has changed
Well, I insert console.log in child render(), it does re-rendered the DOM, so I think the question now becomes if the updating of the child is necessary?
I try to give an answer, with an example that can show what I'm saying. Though, you may want to wait for other people to give other answers too.
Short story: yes, the child Component will be re-rendered, and that's because, being a child of a Component that is being re-rendered, its render() method will be called because of a sort of "waterfall effect": each Component inside a render() method can be seen as a function, thus, if the render() method is called, all the functions inside it are called again, leading to a re-render.
Though, what's important is that, even if the child Component is re-rendered, this does not mean that the DOM will change! Actually, that will not happen, and that's because of the React reconciliation: https://reactjs.org/docs/reconciliation.html.
Basically, React is smart enough to see if something has changed in the DOM, and replace the DOM element that actually needs to change (this is really semplified).
Now, about the example, look at this fiddle:
class Child extends React.Component {
/* Un-commeting this function, you can see that the render() method is not called agian.
shouldComponentUpdate(nextProps, nextState) {
if (JSON.stringify(nextProps) === JSON.stringify(this.props) &&
JSON.stringify(nextState) === JSON.stringify(this.state)) {
return false;
}
return true;
}*/
render() {
console.log("Child's rendering");
return (
<p>Child says "Hello World"</p>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {show: false};
}
render() {
return (
<div>
<button onClick={() => this.setState({show: !this.state.show})}>Toggle</button>
{this.state.show && <p>Parent says: Hello World!</p>}
<Child />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
#import url(https://fonts.googleapis.com/css?family=Montserrat);
body {
font-family: 'Montserrat', sans-serif;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='root'></div>
Each time you click on the button, in the console will be rendered the message Child's rendering, thus the Child Component is running its render() method.
BUT! If you inspect the DOM, when you click the button and the message `Parent says: Hello World" appears on the screen, this is what's happening in the DOM:
As you can see, only the <p> element with the message is changing in the DOM!.
Instead, when you click again the button and the message goes away, this happens:
In this case is the parent <div> element that is changing, and only it, and that's because we have deleted one of its child.
Its necessary Because we’re working with JavaScript, we can change children. We can send special properties to them, decide if we want them to render or not and generally manipulate them to our will.
You can use React's PureComponent if don't want to update Child Component every time when Parent Component updated
You can use shouldComponentUpdate to prevent a rerender of the child component. It can be used to prevent component renderings on a fine-grained level:
You can apply equality checks for different props and state, but also use it for other kind of checks. However, imagine you are not interested in checking each incoming prop by itself, which can be error prone too, but only in preventing a rerendering when nothing relevant (props, state) has changed for the component. That’s where you can use the more broad yet simpler solution for preventing the rerender: React’s PureComponent.
import React, { Component, PureComponent } from 'react';
...
class Square extends PureComponent {
render() {
return <Item>{this.props.number * this.props.number}</Item>;
}
}
React’s PureComponent does a shallow compare on the component’s props and state. If nothing has changed, it prevents the rerender of the component. If something has changed, it rerenders the component.

componentDidUpdate vs componentDidMount

I need to make sure an input element is focused when the following is true:
DOM is available
and properties got changed
Question: Do I need to put my code in both componentDidUpdate and componentDidMount or just componentDidUpdate would be suffice?
private makeSureInputElementFocused() {
if (this.props.shouldGetInputElementFocused && this.inputElement !== null) {
this.inputElement.focus();
}
}
componentDidMount() {
this.makeSureInputElementFocused(); // <-- do i need this?
}
componentDidUpdate() {
this.makeSureInputElementFocused();
}
You have to use both.
componentDidMount()
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. Setting state in this method will trigger a re-rendering.
componentDidUpdate()
componentDidUpdate() is invoked immediately after updating occurs. This method is not called for the initial render.
You also could place it into the render() method which seems like it's appropriate for your case since you always want to check the focus. Then you don't need to put it into componentDidMount() and componentDidUpdate()
Each of your conditions require you to place the code inside 1 function each:
the DOM is available and - componentDidMount
properties got changed - componentDidUpdate
So you have to place inside both functions.
Another option is to call setState() inside componentDidMount, so that componentDidUpdate is invoked.
componentDidUpdate is not called at initial render (see https://reactjs.org/docs/react-component.html#componentdidupdate) so you probably must call it twice as in your example.
componentDidMount()
componentDidMount() will be invoked immediately after a component is mounted. This method will render only once and all the initialization that requires DOM nodes should go here. Setting state in this method will trigger a re-rendering.
componentDidUpdate()
componentDidUpdate() is invoked immediately every time the updating occurs. This method is not called for the initial render.
You can understands more from this below example
import React from 'react';
class Example extends React.Component{
constructor(props) {
super(props);
this.state = {
count: 0
};
}
componentDidMount() {
//This function will call on initial rendering.
document.title = `You clicked ${this.state.count} times`;
}
componentDidUpdate() {
document.title = `You clicked ${this.state.count} times`;
}
render(){
return(
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
)
}
}
export default Example;
You can understand by commenting and un-commenting both methods.
In React v16.7.0-alpha you can use the useEffect hook:
import React, { useEffect, useRef } from "react";
function InputField() {
const inputRef = useRef();
useEffect(() => {
inputRef.current.focus();
});
return <input ref={inputRef} />;
}
From the docs:
If you’re familiar with React class lifecycle methods, you can think
of useEffect Hook as componentDidMount, componentDidUpdate, and
componentWillUnmount combined.
Example
Note: as mentioned, this will not work with class based components.

How to refresh props with React/Redux when user enters a container

I have CompetitionSection which repeats all the competitions from database. When user clicks on one, it redirects him to a Competition Page, loads for a second and renders the page with all the details in it. So far, so good.
But when users goes back to the Competition Section and then click on the second competition, it instantly loads up the previous competition, 0 loading time.
From my point of view, what is failing is that the props of the component are not updating when I render the component (from the second time). Is not a router problem, which was my first instinct because I'm seeing the route.params changing acordingly, but the actions I dispatch to change the props are not dispatching. Here's a bit of code of said component.
class CompetitionPage extends React.Component {
componentWillMount() {
let id = getIdByName(this.props.params.shortname)
this.props.dispatch(getCompAction(id));
this.props.dispatch(getCompMatches(id));
this.props.dispatch(getCompParticipants(id));
this.props.dispatch(getCompBracket(id));
}
render() {
let { comp, compMatches, compBracket, compParticipants } = this.props
...
I tried every lifecycle method I know. component Will/Did Mount, component Will/Did update and I even set shouldUpdate to true and didn't do the trick. As I understand, the problem will be solved with a lifecycle method to dispatch the actions everytime an user enters Competition Page and not just for the first time. I'm running out of options here, so any help will be appreciated.
NOTE: I'm a newbie at React/Redux so I KNOW there are a couple of things there are anti-pattern/poorly done.
UPDATE: Added CompetitionsSection
class CompetitionsSection extends React.Component {
render() {
const {competitions} = this.props;
return (
...
{ Object.keys(competitions).map(function(comp, i) {
return (
<div key={i} className={competitions[comp].status ===
undefined? 'hide-it':'col-xs-12 col-md-6'}>
...
<Link to={"/competitions/"+competitions[comp].shortName}>
<RaisedButton label="Ver Torneo" primary={true} />
</Link>
...
It helps to better understand the lifecycle hooks. Mounting a component is when it is placed on the DOM. That can only happen once until it is removed from the DOM. An UPDATE occurs when new props are passed or setState is called. There are a few methods to troubleshoot when updates are not happening when you think they should:
Ensure that you are changing state in componentDidMount or componentDidUpdate. You cannot trigger an update in componentWillMount.
Make sure that the new props or state are completely new objects. If you are passing an object down in props and you are just mutating the object, it will not trigger an update. For instance, this would not trigger a update:
class CompetitionPage extends React.Component {
constructor(props) {
super(props)
this.state = {
competitions: [ compA, compB ]
}
}
triggerUpdate() {
this.setState({
competitions: competitions.push(compC)
})
}
componentDidMount() {
triggerUpdate()
}
render() {
return(
<div>
Hello
</div>
)
}
This is due to the fact that a new competition is being appended to the array in state. The correct way is to completly create a new state object and change what needs to be changed:
const newCompetitions = this.state.competitions.concat(compC)
this.setState(Object.assign({}, this.state, { competitions: newCompetitions }))
Use ComponentWillRecieveProps on an update to compare previous and current prop values. You can setState here if clean up needs to be done:
Read more about this method in the React documentation:
https://facebook.github.io/react/docs/react-component.html#componentwillreceiveprops

React get props in child component for inner function use

i got a component A:
import React, { Component } from 'react'
import Gmap from '../global/gmap.component'
class RandomPlace extends Component {
render() {
return (
<Gmap address={this.state.random.location} />
which renders among other things, the Gmap component:
class Gmap extends Component {
componentDidMount () {
}
render() {
return (
<div className="gmap-component">
<p>{this.props.address}</p>
This <p>{this.props.address}</p> is well displayed and updated when i hit a "reload" button on component A. At this point, the React Chrome extension shows well the props' address content. And sees it being updated well on the "reload" action.
Problem is, i cant seem to be able to reach the props property address in the internal functions of my component Gmap like componentDidMount() or aCustomFunction().
I have tested this:
componentDidMount () {
console.log('gmap did mount')
this.setState({address: this.props.address})
let x = this.props.address
let y = this.state.address
console.log(x)
console.log(y)
With a constructor at the top of the class:
constructor (props) {
super(props)
this.state = {
address: 'xx'
}
But nothing shows up. I am new to React and sure i am missing something pretty basic but cant see to spot it.
Thanks in advance.
Are you asking how to call a custom function on your child component? If so,
<Gmap address={this.state.random.location} ref={(map) => { this.map = map; }} />
Then
this.map.aCustomFunction()
I'm not entirely sure, but i think it's going like:
In your component A, address={this.state.random.location} set from the state, as you see.
random object fill with call getRandomPlace() in componentDidMount().
So what's going on: at first you render Gmap component you have prop address there with undefined, because on component A didn't call componentDidMount() yet.
Then in component A trigger componentDidMount you get filled object "random" and yuor component Gmap recive normal prop addres, with no indefined. And rerender component with this new adderss prop, but your componentDidMount() in component Gmap has already invoked and doesn't trigger more...
If i'm right, you can set at component A
constructor(){
super();
this.state={
random: {location: "some test value"}
}
}
and you will see this "some test value" instead undefined in your console log.

Resources