componentDidUpdate vs componentDidMount - reactjs

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.

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.

React: State is set after api call, not before [duplicate]

This question already has answers here:
Why does calling react setState method not mutate the state immediately?
(9 answers)
The useState set method is not reflecting a change immediately
(15 answers)
Closed 8 months ago.
I would like to ask why my state is not changing when I do an onClick event. I've search a while ago that I need to bind the onClick function in constructor but still the state is not updating.
Here's my code:
import React from 'react';
import Grid from 'react-bootstrap/lib/Grid';
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
import BoardAddModal from 'components/board/BoardAddModal.jsx';
import style from 'styles/boarditem.css';
class BoardAdd extends React.Component {
constructor(props) {
super(props);
this.state = {
boardAddModalShow: false
};
this.openAddBoardModal = this.openAddBoardModal.bind(this);
}
openAddBoardModal() {
this.setState({ boardAddModalShow: true }); // set boardAddModalShow to true
/* After setting a new state it still returns a false value */
console.log(this.state.boardAddModalShow);
}
render() {
return (
<Col lg={3}>
<a href="javascript:;"
className={style.boardItemAdd}
onClick={this.openAddBoardModal}>
<div className={[style.boardItemContainer,
style.boardItemGray].join(' ')}>
Create New Board
</div>
</a>
</Col>
);
}
}
export default BoardAdd
Your state needs some time to mutate, and since console.log(this.state.boardAddModalShow) executes before the state mutates, you get the previous value as output. So you need to write the console in the callback to the setState function
openAddBoardModal() {
this.setState({ boardAddModalShow: true }, function () {
console.log(this.state.boardAddModalShow);
});
}
setState is asynchronous. It means you can’t call it on one line and assume the state has changed on the next.
According to React docs
setState() does not immediately mutate this.state but creates a
pending state transition. Accessing this.state after calling this
method can potentially return the existing value. There is no
guarantee of synchronous operation of calls to setState and calls may
be batched for performance gains.
Why would they make setState async
This is because setState alters the state and causes rerendering. This
can be an expensive operation and making it synchronous might leave
the browser unresponsive.
Thus the setState calls are asynchronous as well as batched for better
UI experience and performance.
Fortunately setState() takes a callback. And this is where we get updated state.
Consider this example.
this.setState({ name: "myname" }, () => {
//callback
console.log(this.state.name) // myname
});
So When callback fires, this.state is the updated state.
You can get mutated/updated data in callback.
For anyone trying to do this with hooks, you need useEffect.
function App() {
const [x, setX] = useState(5)
const [y, setY] = useState(15)
console.log("Element is rendered:", x, y)
// setting y does not trigger the effect
// the second argument is an array of dependencies
useEffect(() => console.log("re-render because x changed:", x), [x])
function handleXClick() {
console.log("x before setting:", x)
setX(10)
console.log("x in *line* after setting:", x)
}
return <>
<div> x is {x}. </div>
<button onClick={handleXClick}> set x to 10</button>
<div> y is {y}. </div>
<button onClick={() => setY(20)}> set y to 20</button>
</>
}
Output:
Element is rendered: 5 15
re-render because x changed: 5
(press x button)
x before setting: 5
x in *line* after setting: 5
Element is rendered: 10 15
re-render because x changed: 10
(press y button)
Element is rendered: 10 20
Live version
Since setSatate is a asynchronous function so you need to console the state as a callback like this.
openAddBoardModal(){
this.setState({ boardAddModalShow: true }, () => {
console.log(this.state.boardAddModalShow)
});
}
setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use componentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update has been applied. If you need to set the state based on the previous state, read about the updater argument below.
setState() will always lead to a re-render unless shouldComponentUpdate() returns false. If mutable objects are being used and conditional rendering logic cannot be implemented in shouldComponentUpdate(), calling setState() only when the new state differs from the previous state will avoid unnecessary re-renders.
The first argument is an updater function with the signature:
(state, props) => stateChange
state is a reference to the component state at the time the change is being applied. It should not be directly mutated. Instead, changes should be represented by building a new object based on the input from state and props. For instance, suppose we wanted to increment a value in state by props.step:
this.setState((state, props) => {
return {counter: state.counter + props.step};
});
Think of setState() as a request rather than an immediate command to
update the component. For better perceived performance, React may
delay it, and then update several components in a single pass. React
does not guarantee that the state changes are applied immediately.
Check this for more information.
In your case you have sent a request to update the state. It takes time for React to respond. If you try to immediately console.log the state, you will get the old value.
The above solutions don't work for useState hooks.
One can use the below code
setState((prevState) => {
console.log(boardAddModalShow)
// call functions
// fetch state using prevState and update
return { ...prevState, boardAddModalShow: true }
});
This callback is really messy. Just use async await instead:
async openAddBoardModal(){
await this.setState({ boardAddModalShow: true });
console.log(this.state.boardAddModalShow);
}
If you want to track the state is updating or not then the another way of doing the same thing is
_stateUpdated(){
console.log(this.state. boardAddModalShow);
}
openAddBoardModal(){
this.setState(
{boardAddModalShow: true},
this._stateUpdated.bind(this)
);
}
This way you can call the method "_stateUpdated" every time you try to update the state for debugging.
Although there are many good answers, if someone lands on this page searching for alternative to useState for implementing UI components like Navigation drawers which should be opened or closed based on user input, this answer would be helpful.
Though useState seems handy approach, the state is not set immediately and thus, your website or app looks laggy... And if your page is large enough, react is going to take long time to compute what all should be updated upon state change...
My suggestion is to use refs and directly manipulate the DOM when you want UI to change immediately in response to user action.
Using state for this purspose is really a bad idea in case of react.
setState() is asynchronous. The best way to verify if the state is updating would be in the componentDidUpdate() and not to put a console.log(this.state.boardAddModalShow) after this.setState({ boardAddModalShow: true }) .
according to React Docs
Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately
According to React Docs
React does not guarantee that the state changes are applied immediately.
This makes reading this.state right after calling setState() a potential pitfall and can potentially return the existing value due to async nature .
Instead, use componentDidUpdate or a setState callback that is executed right after setState operation is successful.Generally we recommend using componentDidUpdate() for such logic instead.
Example:
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends React.Component {
constructor() {
super();
this.state = {
counter: 1
};
}
componentDidUpdate() {
console.log("componentDidUpdate fired");
console.log("STATE", this.state);
}
updateState = () => {
this.setState(
(state, props) => {
return { counter: state.counter + 1 };
});
};
render() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={this.updateState}>Update State</button>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
this.setState({
isMonthFee: !this.state.isMonthFee,
}, () => {
console.log(this.state.isMonthFee);
})
when i was running the code and checking my output at console it showing the that it is undefined.
After i search around and find something that worked for me.
componentDidUpdate(){}
I added this method in my code after constructor().
check out the life cycle of react native workflow.
https://images.app.goo.gl/BVRAi4ea2P4LchqJ8
Yes because setState is an asynchronous function. The best way to set state right after you write set state is by using Object.assign like this:
For eg you want to set a property isValid to true, do it like this
Object.assign(this.state, { isValid: true })
You can access updated state just after writing this line.

set State is not updating immediately in Reactjs? [duplicate]

This question already has answers here:
Why does calling react setState method not mutate the state immediately?
(9 answers)
The useState set method is not reflecting a change immediately
(15 answers)
Closed 8 months ago.
I would like to ask why my state is not changing when I do an onClick event. I've search a while ago that I need to bind the onClick function in constructor but still the state is not updating.
Here's my code:
import React from 'react';
import Grid from 'react-bootstrap/lib/Grid';
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
import BoardAddModal from 'components/board/BoardAddModal.jsx';
import style from 'styles/boarditem.css';
class BoardAdd extends React.Component {
constructor(props) {
super(props);
this.state = {
boardAddModalShow: false
};
this.openAddBoardModal = this.openAddBoardModal.bind(this);
}
openAddBoardModal() {
this.setState({ boardAddModalShow: true }); // set boardAddModalShow to true
/* After setting a new state it still returns a false value */
console.log(this.state.boardAddModalShow);
}
render() {
return (
<Col lg={3}>
<a href="javascript:;"
className={style.boardItemAdd}
onClick={this.openAddBoardModal}>
<div className={[style.boardItemContainer,
style.boardItemGray].join(' ')}>
Create New Board
</div>
</a>
</Col>
);
}
}
export default BoardAdd
Your state needs some time to mutate, and since console.log(this.state.boardAddModalShow) executes before the state mutates, you get the previous value as output. So you need to write the console in the callback to the setState function
openAddBoardModal() {
this.setState({ boardAddModalShow: true }, function () {
console.log(this.state.boardAddModalShow);
});
}
setState is asynchronous. It means you can’t call it on one line and assume the state has changed on the next.
According to React docs
setState() does not immediately mutate this.state but creates a
pending state transition. Accessing this.state after calling this
method can potentially return the existing value. There is no
guarantee of synchronous operation of calls to setState and calls may
be batched for performance gains.
Why would they make setState async
This is because setState alters the state and causes rerendering. This
can be an expensive operation and making it synchronous might leave
the browser unresponsive.
Thus the setState calls are asynchronous as well as batched for better
UI experience and performance.
Fortunately setState() takes a callback. And this is where we get updated state.
Consider this example.
this.setState({ name: "myname" }, () => {
//callback
console.log(this.state.name) // myname
});
So When callback fires, this.state is the updated state.
You can get mutated/updated data in callback.
For anyone trying to do this with hooks, you need useEffect.
function App() {
const [x, setX] = useState(5)
const [y, setY] = useState(15)
console.log("Element is rendered:", x, y)
// setting y does not trigger the effect
// the second argument is an array of dependencies
useEffect(() => console.log("re-render because x changed:", x), [x])
function handleXClick() {
console.log("x before setting:", x)
setX(10)
console.log("x in *line* after setting:", x)
}
return <>
<div> x is {x}. </div>
<button onClick={handleXClick}> set x to 10</button>
<div> y is {y}. </div>
<button onClick={() => setY(20)}> set y to 20</button>
</>
}
Output:
Element is rendered: 5 15
re-render because x changed: 5
(press x button)
x before setting: 5
x in *line* after setting: 5
Element is rendered: 10 15
re-render because x changed: 10
(press y button)
Element is rendered: 10 20
Live version
Since setSatate is a asynchronous function so you need to console the state as a callback like this.
openAddBoardModal(){
this.setState({ boardAddModalShow: true }, () => {
console.log(this.state.boardAddModalShow)
});
}
setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use componentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update has been applied. If you need to set the state based on the previous state, read about the updater argument below.
setState() will always lead to a re-render unless shouldComponentUpdate() returns false. If mutable objects are being used and conditional rendering logic cannot be implemented in shouldComponentUpdate(), calling setState() only when the new state differs from the previous state will avoid unnecessary re-renders.
The first argument is an updater function with the signature:
(state, props) => stateChange
state is a reference to the component state at the time the change is being applied. It should not be directly mutated. Instead, changes should be represented by building a new object based on the input from state and props. For instance, suppose we wanted to increment a value in state by props.step:
this.setState((state, props) => {
return {counter: state.counter + props.step};
});
Think of setState() as a request rather than an immediate command to
update the component. For better perceived performance, React may
delay it, and then update several components in a single pass. React
does not guarantee that the state changes are applied immediately.
Check this for more information.
In your case you have sent a request to update the state. It takes time for React to respond. If you try to immediately console.log the state, you will get the old value.
The above solutions don't work for useState hooks.
One can use the below code
setState((prevState) => {
console.log(boardAddModalShow)
// call functions
// fetch state using prevState and update
return { ...prevState, boardAddModalShow: true }
});
This callback is really messy. Just use async await instead:
async openAddBoardModal(){
await this.setState({ boardAddModalShow: true });
console.log(this.state.boardAddModalShow);
}
If you want to track the state is updating or not then the another way of doing the same thing is
_stateUpdated(){
console.log(this.state. boardAddModalShow);
}
openAddBoardModal(){
this.setState(
{boardAddModalShow: true},
this._stateUpdated.bind(this)
);
}
This way you can call the method "_stateUpdated" every time you try to update the state for debugging.
Although there are many good answers, if someone lands on this page searching for alternative to useState for implementing UI components like Navigation drawers which should be opened or closed based on user input, this answer would be helpful.
Though useState seems handy approach, the state is not set immediately and thus, your website or app looks laggy... And if your page is large enough, react is going to take long time to compute what all should be updated upon state change...
My suggestion is to use refs and directly manipulate the DOM when you want UI to change immediately in response to user action.
Using state for this purspose is really a bad idea in case of react.
setState() is asynchronous. The best way to verify if the state is updating would be in the componentDidUpdate() and not to put a console.log(this.state.boardAddModalShow) after this.setState({ boardAddModalShow: true }) .
according to React Docs
Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately
According to React Docs
React does not guarantee that the state changes are applied immediately.
This makes reading this.state right after calling setState() a potential pitfall and can potentially return the existing value due to async nature .
Instead, use componentDidUpdate or a setState callback that is executed right after setState operation is successful.Generally we recommend using componentDidUpdate() for such logic instead.
Example:
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends React.Component {
constructor() {
super();
this.state = {
counter: 1
};
}
componentDidUpdate() {
console.log("componentDidUpdate fired");
console.log("STATE", this.state);
}
updateState = () => {
this.setState(
(state, props) => {
return { counter: state.counter + 1 };
});
};
render() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={this.updateState}>Update State</button>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
this.setState({
isMonthFee: !this.state.isMonthFee,
}, () => {
console.log(this.state.isMonthFee);
})
when i was running the code and checking my output at console it showing the that it is undefined.
After i search around and find something that worked for me.
componentDidUpdate(){}
I added this method in my code after constructor().
check out the life cycle of react native workflow.
https://images.app.goo.gl/BVRAi4ea2P4LchqJ8
Yes because setState is an asynchronous function. The best way to set state right after you write set state is by using Object.assign like this:
For eg you want to set a property isValid to true, do it like this
Object.assign(this.state, { isValid: true })
You can access updated state just after writing this line.

event onClick of Button on react js does not work as counter [duplicate]

This question already has answers here:
Why does calling react setState method not mutate the state immediately?
(9 answers)
The useState set method is not reflecting a change immediately
(15 answers)
Closed 8 months ago.
I would like to ask why my state is not changing when I do an onClick event. I've search a while ago that I need to bind the onClick function in constructor but still the state is not updating.
Here's my code:
import React from 'react';
import Grid from 'react-bootstrap/lib/Grid';
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
import BoardAddModal from 'components/board/BoardAddModal.jsx';
import style from 'styles/boarditem.css';
class BoardAdd extends React.Component {
constructor(props) {
super(props);
this.state = {
boardAddModalShow: false
};
this.openAddBoardModal = this.openAddBoardModal.bind(this);
}
openAddBoardModal() {
this.setState({ boardAddModalShow: true }); // set boardAddModalShow to true
/* After setting a new state it still returns a false value */
console.log(this.state.boardAddModalShow);
}
render() {
return (
<Col lg={3}>
<a href="javascript:;"
className={style.boardItemAdd}
onClick={this.openAddBoardModal}>
<div className={[style.boardItemContainer,
style.boardItemGray].join(' ')}>
Create New Board
</div>
</a>
</Col>
);
}
}
export default BoardAdd
Your state needs some time to mutate, and since console.log(this.state.boardAddModalShow) executes before the state mutates, you get the previous value as output. So you need to write the console in the callback to the setState function
openAddBoardModal() {
this.setState({ boardAddModalShow: true }, function () {
console.log(this.state.boardAddModalShow);
});
}
setState is asynchronous. It means you can’t call it on one line and assume the state has changed on the next.
According to React docs
setState() does not immediately mutate this.state but creates a
pending state transition. Accessing this.state after calling this
method can potentially return the existing value. There is no
guarantee of synchronous operation of calls to setState and calls may
be batched for performance gains.
Why would they make setState async
This is because setState alters the state and causes rerendering. This
can be an expensive operation and making it synchronous might leave
the browser unresponsive.
Thus the setState calls are asynchronous as well as batched for better
UI experience and performance.
Fortunately setState() takes a callback. And this is where we get updated state.
Consider this example.
this.setState({ name: "myname" }, () => {
//callback
console.log(this.state.name) // myname
});
So When callback fires, this.state is the updated state.
You can get mutated/updated data in callback.
For anyone trying to do this with hooks, you need useEffect.
function App() {
const [x, setX] = useState(5)
const [y, setY] = useState(15)
console.log("Element is rendered:", x, y)
// setting y does not trigger the effect
// the second argument is an array of dependencies
useEffect(() => console.log("re-render because x changed:", x), [x])
function handleXClick() {
console.log("x before setting:", x)
setX(10)
console.log("x in *line* after setting:", x)
}
return <>
<div> x is {x}. </div>
<button onClick={handleXClick}> set x to 10</button>
<div> y is {y}. </div>
<button onClick={() => setY(20)}> set y to 20</button>
</>
}
Output:
Element is rendered: 5 15
re-render because x changed: 5
(press x button)
x before setting: 5
x in *line* after setting: 5
Element is rendered: 10 15
re-render because x changed: 10
(press y button)
Element is rendered: 10 20
Live version
Since setSatate is a asynchronous function so you need to console the state as a callback like this.
openAddBoardModal(){
this.setState({ boardAddModalShow: true }, () => {
console.log(this.state.boardAddModalShow)
});
}
setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use componentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update has been applied. If you need to set the state based on the previous state, read about the updater argument below.
setState() will always lead to a re-render unless shouldComponentUpdate() returns false. If mutable objects are being used and conditional rendering logic cannot be implemented in shouldComponentUpdate(), calling setState() only when the new state differs from the previous state will avoid unnecessary re-renders.
The first argument is an updater function with the signature:
(state, props) => stateChange
state is a reference to the component state at the time the change is being applied. It should not be directly mutated. Instead, changes should be represented by building a new object based on the input from state and props. For instance, suppose we wanted to increment a value in state by props.step:
this.setState((state, props) => {
return {counter: state.counter + props.step};
});
Think of setState() as a request rather than an immediate command to
update the component. For better perceived performance, React may
delay it, and then update several components in a single pass. React
does not guarantee that the state changes are applied immediately.
Check this for more information.
In your case you have sent a request to update the state. It takes time for React to respond. If you try to immediately console.log the state, you will get the old value.
The above solutions don't work for useState hooks.
One can use the below code
setState((prevState) => {
console.log(boardAddModalShow)
// call functions
// fetch state using prevState and update
return { ...prevState, boardAddModalShow: true }
});
This callback is really messy. Just use async await instead:
async openAddBoardModal(){
await this.setState({ boardAddModalShow: true });
console.log(this.state.boardAddModalShow);
}
If you want to track the state is updating or not then the another way of doing the same thing is
_stateUpdated(){
console.log(this.state. boardAddModalShow);
}
openAddBoardModal(){
this.setState(
{boardAddModalShow: true},
this._stateUpdated.bind(this)
);
}
This way you can call the method "_stateUpdated" every time you try to update the state for debugging.
Although there are many good answers, if someone lands on this page searching for alternative to useState for implementing UI components like Navigation drawers which should be opened or closed based on user input, this answer would be helpful.
Though useState seems handy approach, the state is not set immediately and thus, your website or app looks laggy... And if your page is large enough, react is going to take long time to compute what all should be updated upon state change...
My suggestion is to use refs and directly manipulate the DOM when you want UI to change immediately in response to user action.
Using state for this purspose is really a bad idea in case of react.
setState() is asynchronous. The best way to verify if the state is updating would be in the componentDidUpdate() and not to put a console.log(this.state.boardAddModalShow) after this.setState({ boardAddModalShow: true }) .
according to React Docs
Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately
According to React Docs
React does not guarantee that the state changes are applied immediately.
This makes reading this.state right after calling setState() a potential pitfall and can potentially return the existing value due to async nature .
Instead, use componentDidUpdate or a setState callback that is executed right after setState operation is successful.Generally we recommend using componentDidUpdate() for such logic instead.
Example:
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends React.Component {
constructor() {
super();
this.state = {
counter: 1
};
}
componentDidUpdate() {
console.log("componentDidUpdate fired");
console.log("STATE", this.state);
}
updateState = () => {
this.setState(
(state, props) => {
return { counter: state.counter + 1 };
});
};
render() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={this.updateState}>Update State</button>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
this.setState({
isMonthFee: !this.state.isMonthFee,
}, () => {
console.log(this.state.isMonthFee);
})
when i was running the code and checking my output at console it showing the that it is undefined.
After i search around and find something that worked for me.
componentDidUpdate(){}
I added this method in my code after constructor().
check out the life cycle of react native workflow.
https://images.app.goo.gl/BVRAi4ea2P4LchqJ8
Yes because setState is an asynchronous function. The best way to set state right after you write set state is by using Object.assign like this:
For eg you want to set a property isValid to true, do it like this
Object.assign(this.state, { isValid: true })
You can access updated state just after writing this line.

this.setState() is not updating state [duplicate]

This question already has answers here:
Why does calling react setState method not mutate the state immediately?
(9 answers)
The useState set method is not reflecting a change immediately
(15 answers)
Closed 8 months ago.
I would like to ask why my state is not changing when I do an onClick event. I've search a while ago that I need to bind the onClick function in constructor but still the state is not updating.
Here's my code:
import React from 'react';
import Grid from 'react-bootstrap/lib/Grid';
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
import BoardAddModal from 'components/board/BoardAddModal.jsx';
import style from 'styles/boarditem.css';
class BoardAdd extends React.Component {
constructor(props) {
super(props);
this.state = {
boardAddModalShow: false
};
this.openAddBoardModal = this.openAddBoardModal.bind(this);
}
openAddBoardModal() {
this.setState({ boardAddModalShow: true }); // set boardAddModalShow to true
/* After setting a new state it still returns a false value */
console.log(this.state.boardAddModalShow);
}
render() {
return (
<Col lg={3}>
<a href="javascript:;"
className={style.boardItemAdd}
onClick={this.openAddBoardModal}>
<div className={[style.boardItemContainer,
style.boardItemGray].join(' ')}>
Create New Board
</div>
</a>
</Col>
);
}
}
export default BoardAdd
Your state needs some time to mutate, and since console.log(this.state.boardAddModalShow) executes before the state mutates, you get the previous value as output. So you need to write the console in the callback to the setState function
openAddBoardModal() {
this.setState({ boardAddModalShow: true }, function () {
console.log(this.state.boardAddModalShow);
});
}
setState is asynchronous. It means you can’t call it on one line and assume the state has changed on the next.
According to React docs
setState() does not immediately mutate this.state but creates a
pending state transition. Accessing this.state after calling this
method can potentially return the existing value. There is no
guarantee of synchronous operation of calls to setState and calls may
be batched for performance gains.
Why would they make setState async
This is because setState alters the state and causes rerendering. This
can be an expensive operation and making it synchronous might leave
the browser unresponsive.
Thus the setState calls are asynchronous as well as batched for better
UI experience and performance.
Fortunately setState() takes a callback. And this is where we get updated state.
Consider this example.
this.setState({ name: "myname" }, () => {
//callback
console.log(this.state.name) // myname
});
So When callback fires, this.state is the updated state.
You can get mutated/updated data in callback.
For anyone trying to do this with hooks, you need useEffect.
function App() {
const [x, setX] = useState(5)
const [y, setY] = useState(15)
console.log("Element is rendered:", x, y)
// setting y does not trigger the effect
// the second argument is an array of dependencies
useEffect(() => console.log("re-render because x changed:", x), [x])
function handleXClick() {
console.log("x before setting:", x)
setX(10)
console.log("x in *line* after setting:", x)
}
return <>
<div> x is {x}. </div>
<button onClick={handleXClick}> set x to 10</button>
<div> y is {y}. </div>
<button onClick={() => setY(20)}> set y to 20</button>
</>
}
Output:
Element is rendered: 5 15
re-render because x changed: 5
(press x button)
x before setting: 5
x in *line* after setting: 5
Element is rendered: 10 15
re-render because x changed: 10
(press y button)
Element is rendered: 10 20
Live version
Since setSatate is a asynchronous function so you need to console the state as a callback like this.
openAddBoardModal(){
this.setState({ boardAddModalShow: true }, () => {
console.log(this.state.boardAddModalShow)
});
}
setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use componentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update has been applied. If you need to set the state based on the previous state, read about the updater argument below.
setState() will always lead to a re-render unless shouldComponentUpdate() returns false. If mutable objects are being used and conditional rendering logic cannot be implemented in shouldComponentUpdate(), calling setState() only when the new state differs from the previous state will avoid unnecessary re-renders.
The first argument is an updater function with the signature:
(state, props) => stateChange
state is a reference to the component state at the time the change is being applied. It should not be directly mutated. Instead, changes should be represented by building a new object based on the input from state and props. For instance, suppose we wanted to increment a value in state by props.step:
this.setState((state, props) => {
return {counter: state.counter + props.step};
});
Think of setState() as a request rather than an immediate command to
update the component. For better perceived performance, React may
delay it, and then update several components in a single pass. React
does not guarantee that the state changes are applied immediately.
Check this for more information.
In your case you have sent a request to update the state. It takes time for React to respond. If you try to immediately console.log the state, you will get the old value.
The above solutions don't work for useState hooks.
One can use the below code
setState((prevState) => {
console.log(boardAddModalShow)
// call functions
// fetch state using prevState and update
return { ...prevState, boardAddModalShow: true }
});
This callback is really messy. Just use async await instead:
async openAddBoardModal(){
await this.setState({ boardAddModalShow: true });
console.log(this.state.boardAddModalShow);
}
If you want to track the state is updating or not then the another way of doing the same thing is
_stateUpdated(){
console.log(this.state. boardAddModalShow);
}
openAddBoardModal(){
this.setState(
{boardAddModalShow: true},
this._stateUpdated.bind(this)
);
}
This way you can call the method "_stateUpdated" every time you try to update the state for debugging.
Although there are many good answers, if someone lands on this page searching for alternative to useState for implementing UI components like Navigation drawers which should be opened or closed based on user input, this answer would be helpful.
Though useState seems handy approach, the state is not set immediately and thus, your website or app looks laggy... And if your page is large enough, react is going to take long time to compute what all should be updated upon state change...
My suggestion is to use refs and directly manipulate the DOM when you want UI to change immediately in response to user action.
Using state for this purspose is really a bad idea in case of react.
setState() is asynchronous. The best way to verify if the state is updating would be in the componentDidUpdate() and not to put a console.log(this.state.boardAddModalShow) after this.setState({ boardAddModalShow: true }) .
according to React Docs
Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately
According to React Docs
React does not guarantee that the state changes are applied immediately.
This makes reading this.state right after calling setState() a potential pitfall and can potentially return the existing value due to async nature .
Instead, use componentDidUpdate or a setState callback that is executed right after setState operation is successful.Generally we recommend using componentDidUpdate() for such logic instead.
Example:
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends React.Component {
constructor() {
super();
this.state = {
counter: 1
};
}
componentDidUpdate() {
console.log("componentDidUpdate fired");
console.log("STATE", this.state);
}
updateState = () => {
this.setState(
(state, props) => {
return { counter: state.counter + 1 };
});
};
render() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={this.updateState}>Update State</button>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
this.setState({
isMonthFee: !this.state.isMonthFee,
}, () => {
console.log(this.state.isMonthFee);
})
when i was running the code and checking my output at console it showing the that it is undefined.
After i search around and find something that worked for me.
componentDidUpdate(){}
I added this method in my code after constructor().
check out the life cycle of react native workflow.
https://images.app.goo.gl/BVRAi4ea2P4LchqJ8
Yes because setState is an asynchronous function. The best way to set state right after you write set state is by using Object.assign like this:
For eg you want to set a property isValid to true, do it like this
Object.assign(this.state, { isValid: true })
You can access updated state just after writing this line.

Resources