Can someone demonstrate how setState is asynchronous like showing the problem and how/why?
this is the code i tried
class App extends Component {
constructor() {
super();
this.state = {
counter: 0,
};
this.mengUbah = this.mengUbah.bind(this);
}
mengUbah(){
this.setState({counter: this.state.counter + 1});
}
render() {
return (
<div>
<button onClick={this.mengUbah}>CLICK HERE</button>
<h1>{this.state.counter}</h1>
</div>
);
}
}
but i think those code works perfectly so i can't tell the asynch problem.
I've tried to read all about setState but still can't understand
Guess the output of the following,
class Example extends React.Component {
constructor() {
super();
this.state = {
val: 0
};
}
componentDidMount() {
this.setState({val: this.state.val + 1});
console.log(this.state.val); // first log
this.setState({val: this.state.val + 1});
console.log(this.state.val); // second log
setTimeout(() => {
this.setState({val: this.state.val + 1});
console.log(this.state.val); // third log
this.setState({val: this.state.val + 1});
console.log(this.state.val); // fourth log
}, 0);
}
render() {
return null;
}
};
Related
Hi I am creating a chat bot using react.My code is:
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
random : '',
}
}
componentDidMount(){
addResponseMessage('Welcome to React Bot! Type start');
return this.setState({random : Math.floor(Math.random()*10000)});
}
handleNewUserMessage = (newMessage) => {
fetch('http://localhost:5005/webhooks/rest/webhook', {
method: 'POST',
headers : new Headers(),
body:JSON.stringify({"sender":this.state.random, "message": newMessage}),
}).then((res) => res.json())
.then((data) => {
var first = data[0];
var mm= first.text;
var i;
console.log(mm)
toggleMsgLoader();
setTimeout(() => {
toggleMsgLoader();
if (data.length < 1) {
addResponseMessage("I could not get....");
}
else{
addResponceMessage(mm)
}
}
}
handleQuickButtonClicked = (e) => {
addUserMessage(e);
this.handleNewUserMessage(e);
setQuickButtons([]);
}
render() {
return (
<Widget
title="Rasa Sample Bot"
subtitle="Asistente virtual"
senderPlaceHolder="Type here ..."
handleNewUserMessage={this.handleNewUserMessage}
handleQuickButtonClicked={this.handleQuickButtonClicked}
badge={1}
/>
);
}
}
When user give to messages to my bot.It will call handleNewUsermMessage() and execute and give responses to user. body:JSON.stringify({"sender":this.state.random, "message": newMessage}), this code for when user refreshing the page that sender id will be change. But here every message it will create a random Id. I don't want every message. Whenever user refresh the page then only i want create random id.
How to solve this. Please help. Thanks in advance
Define in your state
class Button extends React.Component {
constructor(props) {
super(props);
this.state = {
random: Math.floor(Math.random()*100),
}
}
handleClick = () => {
this.setState({random: this.min + (Math.random() * (this.max - this.min))});
};
render() {
return (
<div>
<button onClick={this.handleClick}>Click me</button>
{this.state.random}
</div>
);
}
}
try this write in componentDidMount.
class Button extends React.Component {
constructor(props) {
super(props);
this.state = {
random : '',
}
}
componentDidMount() {
this.setState({random : Math.floor(Math.random()*100)});
}
handleClick = () => {
this.setState({random: this.min + (Math.random() * (this.max - this.min))});
};
render() {
return (
<div>
<button onClick={this.handleClick}>Click me</button>
{this.state.random}
</div>
);
}
}
In react when you refresh the browser the components remounts. So to generate random number on refresh you should call the random number generating function in componentDidMount() lifecycle method. The below code will work.
class Button extends React.Component {
constructor(props) {
super(props);
this.state = {
random: null,
}
}
min = 1;
max = 100;
generateRandom =()=>{
this.setState({random: this.min + (Math.random() * (this.max
this.min))
}});
componentDidMount(){
this.generateRandom();
}
handleClick = () => {
this.generateRandom();
};
render() {
return (
<div>
<button onClick={this.handleClick}>Click me</button>
{this.state.random}
</div>
);
}
}
this.state = {
random: Math.floor(Math.random()*100)
}
Just Update the above line in the constructor and it will all work just fine
I am a newbie for react js. how to manage two Countdown timers first start and second is stop after 5-second interval second start and first stop.
it work for single Clock successful but add two clocks then first only start and not stop while second not start I don't know how do this ?.
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
isActive: true
};
}
componentDidMount() {
this.intervalId = setInterval(() => {
this.randomCallObject();
}, 5000);
}
randomCallObject() {
this.setState({
Active: !this.state.isActive
});
}
render() {
let clock= {
time: 150,
isActive:this.state.isActive
}
let clock2= {
time: 100,
isActive:!this.state.isActive
}
return (
<div className="container">
<Clcok ClockData={clock}/>
<Clcok ClockData={clock2}/>
</div>
);
}
}
import React, { Component } from "react";
const TOTAL_MINUTES = 60;
export default class ClockComponent extends Component {
constructor(props) {
super(props);
this.state = {
time: props.ClockData.time,
isActive: props.ClockData.isActive
};
}
componentDidMount() {
const { isActive } = this.state;
if (isActive === true) {
this.intervalId = setInterval(() => {
const { time } = this.state;
if (time > 0) {
this.setState({
time: time - 1
});
}
}, 1000);
}
}
componentWillUnmount() {
clearInterval(this.intervalId);
}
render() {
const { time } = this.state;
let minutes ="" + Math.floor((time % (TOTAL_MINUTES * TOTAL_MINUTES))/ TOTAL_MINUTES);
let seconds = "" + Math.floor(time % TOTAL_MINUTES);
if (isNaN(minutes) || isNaN(seconds)) {
return null;
}
if (minutes.length === 1) {
minutes = `0${minutes}`;
}
if (seconds.length === 1) {
seconds = `0${seconds}`;
}
return (
<div className="row">
<div className="col-md-1">
<div>
{minutes}:{seconds}
</div>
</div>
</div>
);
}
}
when clock data comes from props so take simple objects when isActive flag is true then clock timer on when isActive false then timer stop
To learn how to handle setInterval with React, I suggest you read the following blog post by Dan Abramov:
Making setInterval Declarative with React Hooks
In it, he explains how to use setInterval using React Hooks and also how to do it using a class component. On the post, there is also a link to a CodeSandbox example where you can see it in action.
What I did was create another CodeSandbox where you can see how you could apply this example to run multiple timers:
https://codesandbox.io/embed/timers-l6me1
I've used React Hooks in the example because they don't require a lot of code.
I hope it helps.
edit #1
Here is an example of a Counter component taken directly from the mentioned article, and adapted to fit the latter example.
class Counter extends React.Component {
state = {
count: 0,
delay: 1000,
isRunning: true
};
constructor(props) {
super(props);
this.state = { ...this.state, ...props };
}
componentDidMount() {
this.interval = setInterval(this.tick, this.state.delay);
}
componentDidUpdate(prevProps, prevState) {
if (prevState.delay !== this.state.delay) {
this.startInterval();
}
}
componentWillUnmount() {
clearInterval(this.interval);
}
startInterval = () => {
clearInterval(this.interval);
this.interval = setInterval(this.tick, this.state.delay);
console.log(this.interval);
};
tick = () => {
this.setState({
count: this.state.count + 1
});
};
handleDelayChange = e => {
this.setState({ delay: Number(e.target.value) });
};
toggleCounter = () => {
console.log(this.state.isRunning);
if (this.state.isRunning) {
clearInterval(this.interval);
} else {
this.startInterval(this.state.delay);
}
this.setState({
count: 0,
isRunning: !this.state.isRunning
});
};
render() {
const {
state: { isRunning, delay, count },
toggleCounter,
handleDelayChange
} = this;
return (
<>
<h1>{count}</h1>
<input value={delay} onChange={handleDelayChange} />
<button onClick={toggleCounter}>{isRunning ? "stop" : "start"}</button>
</>
);
}
}
I want to update the the state on the basis of a condition.
Please refer to the code and point out the problem in either the logic or code.
class App extends Component {
constructor(props) {
super(props);
this.state = {
backImgIndex: 1
};
this.changeSlide = this.changeSlide.bind(this);
}
changeSlide() {
if (this.state.backImgIndex === 3) ({
this.setState = {
backImgIndex: 1
});
} else {
this.setState = ({
backImgIndex: this.state.backImgIndex + 1
});
}
}
render() {
const imageURL = '/backImg/b' + this.state.backImgIndex + '.jpg';
return (
<Fragment>
<BackgroundSlider backurl={imageURL} />
<div className="slider">
<div className="left-arrow" style={{}} onClick={this.changeSlide} />
</div>
</Fragment>
);
}
}
export default App;
Is there any other way to update the same.
The end goal is to update the state which trigger the update in the background image upon the press of .left arrow.
Can div be used for such an event ?
You are doing the update in the wrong way. setState is a function that should be called in order for updating the state. In fact, you are overriding such function:
this.setState = {
backImgIndex: 1
};
So, what you need is to call setState and pass in the part of the state you wanna update:
this.setState({ backImgIndex: 1 });
This works:
changeSlide() {
if (this.state.backImgIndex === 3) {
this.setState({
backImgIndex: 1
});
} else {
this.setState({
backImgIndex: this.state.backImgIndex + 1
});
}
}
Final code
class App extends Component {
constructor(props) {
super(props);
this.state = {
backImgIndex: 1
};
this.changeSlide = this.changeSlide.bind(this);
}
changeSlide() {
if (this.state.backImgIndex === 3) {
this.setState({
backImgIndex: 1
});
} else {
this.setState({
backImgIndex: this.state.backImgIndex + 1
});
}
}
render() {
const imageURL = '/backImg/b' + this.state.backImgIndex + '.jpg';
return (
<Fragment>
<BackgroundSlider backurl={imageURL} />
<div className="slider">
<div className="left-arrow" style={{}} onClick={this.changeSlide} />
</div>
</Fragment>
);
}
}
Wrong syntax in setState.
Plus, i would recommend preparing the new state before setting it:
changeSlide() {
let imgI=this.state.backImgIndex;
imgI=(imgI===3)?1:imgI+1;
this.setState({ backImgIndex: imgI});
}
Actually, a better option (because State Updates May Be Asynchronous):
changeSlide() {
this.setState((state,props)=>(state.backImgIndex===3?{ backImgIndex: 1}:{ backImgIndex: state.backImgIndex+1}));
}
First of all, I suggest you to use the ES6 syntax for more clarity :
class App extends Component {
constructor(props) {
super(props);
this.state = {
backImgIndex: 1
};
}
changeSlide = () => {
if (this.state.backImgIndex === 3) {
this.setState = ({
backImgIndex: 1
});
} else {
this.setState = ({
backImgIndex: this.state.backImgIndex + 1
});
}
}
render() {
const imageURL = `/backImg/b'${this.state.backImgIndex}.jpg`;
return (
<Fragment>
<BackgroundSlider backurl={imageURL} />
<div className="slider">
<div className="left-arrow" style={{}} onClick={this.changeSlide} />
</div>
</Fragment>
);
}
}
export default App;
I changed your function to an arrow function, and used the template string for your imageURL.
I think that the problem is in your setState. Can you please log the result of this.state.backImgIndex after updating the state ?
EDIT : As pointed out in the other comments, you're updating your state the wrong way. I corrected it in this example so you can have a clean example
Console.log printing the incremented value, but value not updated in button
'use strict';
const e = React.createElement;
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { val: 0 };
}
render() {
return e(
'button',
{
onClick: () => {
this.state.val = this.state.val + 1
console.log(this.state.val)
}
},
'Like' + this.state.val // here Like 1 should be displayed
);
}
}
const domContainer = document.querySelector('#root');
ReactDOM.render(e(Counter), domContainer);
You should never update state directly. Always use setState
this.state.val = this.state.val + 1; // bad
this.setState((state) => ({ // good
val: state.val + 1
}))
Otherwise React will not "see" the update and will not re-render.
You have to use setState to update the state. and state update is asynchronous call so you have to use call back functions to check weather store is updated or not.
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { val: 0 };
this.updateState = this.updateState.bind(this);
}
updateState(){
this.setState({val : this.state.val + 1 }, function(){
console.log(this.state.val)
})
}
render() {
return e(
'button',
{
onClick: () => {this.updateState()
}
},
'Like' + this.state.val
);
}
}
You have to update React state via this.setState() function. Otherwise, the component does not re-render. That's basic of React. You should read more React documents or do some tutorials.
You can read more here!
In React I am trying to make a button increment a value stored in state.
However using the code below function my value is set undefined or NaN when using handleClick.
class QuestionList extends React.Component {
constructor(props) {
super(props);
this.state = {value: 0};
// This binding is necessary to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
}
handleClick = (prevState) => {
this.setState({value: prevState.value + 1});
console.log(this.state.value)
}
Can you tell me why this is happening? it should be correct according to the docs here:
https://facebook.github.io/react/docs/state-and-lifecycle.html
Because you are using the handleClick function incorrectly. Here:
handleClick = (prevState) => { .... }
prevState will be an event object passed to handleClick function, you need to use prevState with setState, like this:
handleClick = () => {
this.setState(prevState => {
return {count: prevState.count + 1}
})
}
Another issue is, setState is async so console.log(this.state.value) will not print the updated state value, you need to use callback function with setState.
Check more details about async behaviour of setState and how to check updated value.
Check the working solution:
class App extends React.Component {
constructor(props){
super(props);
this.state={ count: 1}
}
onclick(type){
this.setState(prevState => {
return {count: type == 'add' ? prevState.count + 1: prevState.count - 1}
});
}
render() {
return (
<div>
Count: {this.state.count}
<br/>
<div style={{marginTop: '100px'}}/>
<input type='button' onClick={this.onclick.bind(this, 'add')} value='Inc'/>
<input type='button' onClick={this.onclick.bind(this, 'sub')} value='Dec'/>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='container'></div>
set state is async so you wont see the value update when the console.log happens. You should have the state value printed out on the UI so you can see whats happening. To fix the console log try this.
class QuestionList extends React.Component {
constructor(props) {
super(props);
this.state = {value: 0};
}
handleClick = (prevState) => {
this.setState({value: prevState.value + 1}, () => {
console.log(this.state.value)
});
}
NOTE: when you define an inline lambda (arrow function) for a react class this is bound correctly so you dont need to bind it in the constructor.
also you can change the way you pass the previous number if its just a state increment like this
handleClick = () => {
this.setState({value: this.state.value + 1}, () => {
console.log(this.state.value)
});
}
Hello there, try these codes to increment your value
class Counter extends React.Component{
constructor(props){
super(props);
this.addOne = this.addOne.bind(this);
this.state = {
count : 0
}
}
addOne() { // addOne as HandleClick
this.setState((preState) => {
return {
count : preState.count + 1
};
});
}
render() {
return (
<div>
<h1>Count : {this.state.count}</h1>
<button onClick={this.addOne}>+1</button>
</div>
);
}
}
ReactDOM.render(<Counter />, document.getElementById('YOUR-ID'));
class SkuVariantList extends React.Component {
constructor(props) {
super(props)
this.state = {
clicks: 0
};
this.clickHandler = this.clickHandler.bind(this)
}
componentDidMount() {
this.refs.myComponentDiv.addEventListener('click', this.clickHandler);
}
componentWillUnmount() {
//this.refs.myComponentDiv.removeEventListener('click', this.clickHandler);
}
clickHandler() {
var clk = this.state.clicks
this.setState({
clicks: clk + 1
});
}
render() {
let children = this.props.children;
return (
<div className="my-component" ref="myComponentDiv">
<h2>My Component ({this.state.clicks} clicks})</h2>
<h3>{this.props.headerText}</h3>
{children}
</div>
);
}
}
Try this out
class QuestionList extends React.component {
constructor(props){
super(props)
this.state = {
value : 0
}
}
handleClick(){
this.setState({
value : this.state.value + 1
})
}
render(){
return( <button type="button" onClick={this.handleClick.bind(this)}> {this.state.value} </button> )
}
}
Note that when you set a state, it triggers the render function, which will reflect the current state. Try it out in the browser!
import React from 'react'
class App extends React.Component{
constructor(){
super()
this.state = {
count: 0
}
this.handleClick = this.handleClick.bind(this)
}
handleClick(){
this.setState(prevState => {
return {
count: prevState.count + 1
}
})
}
render(){
return(
<div style = {{display: 'flex', fontSize: 30, flexDirection: 'column', alignItems:'center'}}>
<h1>{this.state.count}</h1>
<button onClick = {this.handleClick}>Change</button>
</div>
)
}
}
export default App
This is the shortest code for that. First, initialize the state, then perform a method to increment.
state = {
counter: 0
}
increaseHandler = () => {
let counter = this.state.counter
counter += 1
this.setState({counter: counter})
}
You can do it this way also where we do both increment and decrement operation with same function making it more modular and redable
class CounterApp extends React.Component{
constructor(){
super();
//here count is initially assigned with 0
this.state ={
count:0
}
}
//when we click Increment or Decrement +1 or -1 is passed to step and the value gets changed it gets updated to the view
increment = (step) =>{
this.setState({
count:this.state.count + step
})
}
render(){
const { count } = this.state;//same as const count = this.state.count;
return(
<div>
<div className="counter-app">
<h2 className="value">{count}</h2>
<button onClick={() => this.increment(+1)}>Increment</button>
<button onClick={() => this.increment(-1)}>Decrement</button>
</div>
</div>
)
}
}