Render called on every setState when using touch gestures - reactjs

I have a problem using touch gestures in my react.js app. The problem is that the render() function is called on every setState call and not just at the end. This only happens when using Hammer.js to handle the tap. If using a regular button the render() function is only called once.
A few things to note:
I have also tried using react-hammerjs and ZingTouch with exactly the same result.
In the example i just use the Tap "gesture" but the result is the same if using for example the Swipe gesture.
I tried to use MobX for state instead. But again with the same result.
Here is my example that I have tried to make as simple as possible (the example does not make sense, but illustrates the problem):
import React from 'react';
import ReactDOM from 'react-dom';
import Hammer from 'hammerjs';
class Game extends React.Component {
constructor(props) {
super(props);
this.state = { value: 1 };
}
action() {
console.log(1)
this.setState({ value: 1 });
console.log(2)
this.setState({ value: 2 });
console.log(3)
this.setState({ value: 3 });
console.log(4)
this.setState({ value: 4 });
console.log(5)
}
componentDidMount() {
this.hammer = Hammer(this._touchdiv);
this.hammer.on('tap', () => this.action());
}
componentWillUnmount() {
this.hammer.off('tap', this.action)
}
render() {
console.log('Render');
return (
<div>
{this.state.value}
<div ref={(el) => this._touchdiv = el}> Touch div</div>
<button onClick={() => this.action()} value='update' >Normal button</button>
</div>
);
}
}
ReactDOM.render(<Game />, document.getElementById('root'));
The console output when using the regular button:
1
2
3
4
5
Render
The console output when using the "touch div":
1
Render
2
Render
3
Render
4
Render
5
I have tried to google it but could not find any similar examples.
Any idea what is happening? Any possible solution is welcome.
Edit 1:
ReyHaynes suggested that the ref could be the problem. I tried to change
<div ref={(el) => this._touchdiv = el}> Touch div</div>
to
<div className='xxx'> Touch div</div>
and changed
this.hammer = Hammer(this._touchdiv);
to
this.hammer = Hammer(document.getElementsByClassName("xxx")[0]);
The result is exactly the same. Yes, this is dirty code but it illustrates that the problem exists without using refs.

When using refs, once state changes, you re-render all the components of your UI that depend on that state.
React will take care of making sure only the right bits of the DOM is updated, making the whole thing efficient but render is called to check for the necessary changes.
Here's the docs on that: https://reactjs.org/docs/refs-and-the-dom.html
So essentially, this part of the touch code causes the render() to run:
ref={(el) => this._touchdiv = el}

Checking the call stack it seems like it's different how the callback is triggered.
Hammer will just call the callback if the gesture is recognized.
React catches the click event and sets the flag 'isBatchingUpdates' to true, making the render to wait until all setState are done.
Edit:
Found this article explaning it: https://itnext.io/react-setstate-usage-and-gotchas-ac10b4e03d60
"Currently (React 16 and earlier), only updates inside React event handlers are batched by default."

Related

How to change state of component from anywhere without Redux?

Is this bad practices or not ?
export state change function from component
import it from other file.
call the function to change state?
In this way we can change some component state from anywhere.
For example...
We want to change the Model.js state from anywhere.
Modal.js
import React from 'react';
export let toggleModal;
export default class Modal extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false,
};
toggleModal = this.toggleModal;
}
toggleModal = () => {
this.setState({ open: !this.state.open });
};
render() {
const { open } = this.state;
return <div style={{ color: 'red' }}>{open && 'Hello Modal'}</div>;
}
}
App.js(Some Top Level component)
import React from 'react';
import Modal from './Modal';
export default () => (
<>
...
<Modal />
...
</>
);
Somewhere.js
import React from 'react';
import {toggleModal} from './Modal';
export default () => (
<>
<h1>Hello!</h1>
<button onClick={() => toggleModal()}>open Modal!</button>
</>
);
  
But there is no reference in React Official docs, so is this bad practices ?
What React Docs recommends...
Just passing function props to change parent state from parent to children
Use context
Redux or Mobx
But, these are too complex for me.
Example code here
https://next.plnkr.co/edit/37nutSDTWp8GGv2r?preview
Everything seems pretty much overwhelming and difficult at the beginning. But as we get out hands on them, it's give us more confidence to dig into.
I would recommend to use redux that's how we tackled props drilling problem. You can dispatch a action and connect reducer to corresponding component which upon updating state will re render. This is what I recommend to most of the people to learn the tale of redux with a real life example:
Understanding Redux: The World’s Easiest Guide to Beginning Redux
Apart from this you can take Dan Abramov, author of the library, free redux course on egghead.io:
Getting Started with Redux
The problem you run into, almost immediately like your code example does is this:
It will not work: your toggleModal() method expects a this to refer to an actual component instance. When your onClick() handler fires you invoke toggleModal() as a plain function. The this context will be wrong, and so at best (in your example) you will get an error because you try to invoke something undefined, at worst (in general) you end up invoking the wrong method.
When you think about it, for any non-trivial React component you will have a hard time obtaining a reference to the actual instance that is currently being used: you have to make sure that you are not forgetting to invoke the method on the right component instance and also you have to consider that instances may be created/destroyed 'at will' for whatever reason. For example: what if your component is rendered indirectly as part of some other component's render() method? Multiple layers of indirection like that make it even harder.
Now, you could fix all that by abusing ref with abandon but you will find that now you have to keep track of which ref refers to what particular instance, if you happen to have multiple of the components to consider in one render tree...
Whenever you think one component needs to handle the state of its siblings, the solution is usually to lift the state one level up.
export default class Modal extends React.Component {
render() {
const { isOpen } = this.props;
return <div style={{ color: 'red' }}>{isOpen && 'Hello Modal'}</div>;
}
}
export default class Home {
this.state = {
isOpen: false,
};
toggleModal = () => {
this.setState({ isOpen: !this.state.isOpen });
}
render() {
const { isOpen } = this.state;
return (
<>
<h1>Hello {name}!</h1>
<button onClick={() => this.toggleModal()}>open Modal!</button>
<Modal isOpen={isOpen}/>
<p>Start editing and see your changes reflected here immediately!</p>
</>
)
}
}
This way the Home handle the state and your problem is solved.
This can get annoying if the state needs to be "drilled down" to children, that's a problem than redux or react-context can solve.
Here <Modal /> is the child component. So to call a function in a child component you can simply use Ref.
You can refer this page to get more info about Ref.
You can assign a class variable as a ref to this child and use this class variable as an object to call its function.
I found if in special case, my way is okay.
Special case means something like customAlert component.
It is okay only one instance of customAlert component mounted at a time in App.
To achieve this...
1.Use ref to access and change DOM
2.attach state changing function or component to window and call window.function
3.my case: export state changing function and import it from other file.
And here is how to do with react Context
https://next.plnkr.co/edit/EpLm1Bq3ASiWECoE?preview
I think Redux is overkill if the main thing you are interested in is to make some states-like data available and updatable throughout your App without props drilling.
For that purpose, a much simpler approach (maybe not available at the time the question was posted?) is to use react context: https://frontend.turing.edu/lessons/module-3/advanced-react-hooks.html
"context - an API given to us by React, allowing for the passing of
information to child components without the use of props
[...]
useContext - a react hook, allowing functional components to take
advantage of the context API"

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