React.js Value not updated on button - reactjs

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!

Related

State won't stay updated

After I use setState in getClients(), the state clientOptions is showed correctly. But when I try to pass it on to a child component it is an empty array. I've tried logging it again after componentDidMount and there it seems that the state clientOptions is resetted to its original state ([]). Sorry if this seems like a noob question, I'am pretty new to react.
class Main extends React.Component {
constructor(props) {
super(props);
this.state = {
clientFilter: 'ALL',
positionFilter: 'ALL',
clientOptions: []
};
}
componentDidMount = () => {
this.getClients()
this.getTitles()
console.log('this one shows only []: ' + this.state.clientOptions)
}
getClients = () => {
axios.get('http://localhost:5000/clients')
.then((response) => {
let clientObj = [{value: 'ALL', label: 'ALL'}];
const clientOptions = []
response.data.forEach(function (client, index) {
clientObj.push({value: client.name, label: client.name})
});
clientOptions.push({'options' : clientObj});
this.setState(prevState =>{
return{
...prevState,
clientOptions : clientOptions
}
})
console.log('this one works: ' + this.state.clientOptions)
});
}
As requested the state passed on to the child:
render() {
return (
<div className="main">
<Header
clientOptions={this.state.clientOptions}
/>
</div>
);
}

Demonstration of setState?

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;
}
};

How can I test a component click which requires a function from a parent component?

I'm trying to write tests for my Reactjs application ( I'm very new to testing this ), but I can't seem to grasp how it works properly.
Below is my Component, what I want to test is handleRegisterFieldClick().
I've seen examples of mocking a click function but since the function I need to call is one passed from a parent component, how can I simulate that? I want to check if state.class = 'clickedSquare' after calling handleRegisterFieldClick().
export default class Square extends Component {
constructor(props) {
super(props)
this.state = {
fieldcell: props.field,
value: props.value,
class: props.class,
xPos: props.xPos,
yPos: props.yPos,
clicked: props.clicked
}
this.handleClick = this.handleClick.bind(this);
this.handleRegisterFieldClick = this.handleRegisterFieldClick.bind(this);
}
handleClick() {
if(this.state.fieldcell){
if (this.props.clicked) {
this.setState({
class: 'square'
})
} else {
this.setState({
class: 'clickedSquare'
})
}
}
}
handleRegisterFieldClick(){
if(this.state.fieldcell){
this.handleClick()
var params = {
xPos: this.state.xPos,
yPos: this.state.yPos
}
this.props.registerFieldClick(params)
}
}
render() {
return (
<button className={this.state.class} onClick={this.handleRegisterFieldClick} background={this.state.backgroundcolor}>
{this.state.value !== 0 ? this.state.value : null}
</button>
);
}
}
Perhaps something like this
const timeout = 'some value';
const timeout2 = 'some other value';
componentDidMount() {
setTimeout(() => {
this.handleRegisterFieldClick();
setTimeout(() => {
//Since setState is asynchronous were using a second timeout
//check the state.class condition here.
}, timeout2);
}, timeout);
}

How to update react state that has object?

I have state in react that includes object called increment. Inside that object i have a property called count with a value of 0.
Does anyone know how to increment count value with a button click?
import React, { Component } from 'react';
class App extends Component {
constructor(){
super();
this.state = {
increment:{
count:0
}
}
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
this.setState(prevState => {
return {
increment.count: prevState.increment.count + 1
}
})
}
render() {
return (
<div>
<h1>{this.state.increment.count}</h1>
<button onClick={this.handleClick}>Change!</button>
</div>
)
}
}
export default App;
React gives me error called Parsing error: Unexpected token, expected ","
Your syntax of updating state is wrong. you can't add key as increment.count. Here is correct syntax.
handleClick() {
this.setState(prevState => {
return {
increment: {
count: prevState.increment.count + 1
}
}
})
}
handleClick() {
this.setState(prevState => ({
increment: {
count: prevState.increment.count + 1
},
})
}

Incrementing state value by one using React

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>
)
}
}

Resources