1

I have been testing the change of states to be able to depend on them and calculate others but I have several results depending on the implementation, and there is one in particular that I do not know or have no idea of what is happening or why it gives that result, pay attention to the console.log()

case: 1

const [state, setState] = useState({count: 0});

const handleCount = () => {
    console.log(state); // prints {count: 0}
    setState(prevState => {
      prevState.count = prevState.count + 1;
      return prevState;
    });
    console.log(state); // prints {count: 1}
  }

useEffect(() => {
    console.log('has changed.. ' + state.count)
  }, [state]); // in this case this doesn't show any changes, so isn't renders anything, I need to render this value

// in render
<Button onClick={() => handleCount()}>
   Click {state.count}
</Button>

case: 2

const handleCount = () => {
    console.log(state); // prints {count: 0}
    setStateV(prevState => ({...prevState, count: prevState.count + 1}));
    console.log(state); // prints {count: 0}
  }

useEffect(() => {
    console.log('has changed.. ' + state.count)
  }, [state]); // it show that changed, but I cant depend on this because it haven't changed when I needed it

case: 3

const [state, setState] = useState(0);
const handleCount = () => {
  console.log(state); // prints 0
  setState(state => state + 1);
  console.log(state); // prints 0 it supposed to be 1!
}

I have read this but not worked at all

So, I need help to understand what is going on please...

skyboyer
  • 22,209
  • 7
  • 57
  • 64
ViT4RGh0ST
  • 13
  • 3
  • Does this answer your question? [React setState not updating state](https://stackoverflow.com/questions/41446560/react-setstate-not-updating-state) – Ajeet Shah May 23 '20 at 20:36

5 Answers5

1

React uses Object.is to compare the state object {count: 0} in your case. In first case you are just mutating the property count and returning the same object. That's why react thinks that state has not changed.Try the snippet bellow

const myObj = { count: 0};
myObj.count = 3;

console.log(Object.is(myObj, myObj)); // returns true

But if you want to use an object inside useState(), when you make an update to the state you should always return a new object with Object.assign or by just simply destructuring the prevState object like this.


const handleCount = () => {
    setState(prevState => {
         // if using Object.assign
         // return Object.assign(prevState, {count: prevState.count + 1})
         return {...prevState, count: prevState.count + 1}
    });
  }

Or for a simple count variable you can just use

const [count, setCount] = useState(0);

const handleCount = () => {
  setCount(prevCount => (prevCount + 1))
}
subashMahapatra
  • 6,339
  • 1
  • 20
  • 26
0

Actually you're mutating the prevState argument which is giving you wrong results, try following:

setState(prevState => {
  const count = prevState.count + 1
  return { ...prevState, count }
})
Muhammad Ali
  • 2,538
  • 2
  • 16
  • 21
0

Try this:


const handleCount = () => {
    console.log(state);
    setState({...state, count: (state.count + 1)});
    console.log(state);
}

Jackson D
  • 130
  • 6
0

Functional setState doesn't have callback function option (which is available in this.setState of class component) because it has useEffect. Try this and check the console logs:

const handleCount = () => {
  console.log('initial state', state) // prints {count: 0}
  setState((prevState) => ({ ...prevState, count: prevState.count + 1 }))
  console.log(
    'state after Calling Async seState might not print latest state',
    state
  ) // prints {count: 0}
}


useEffect(() => {
  console.debug('state changed', state)
  // first print: { count: 0 } at mount
  // second print: { count: 1 }
}, [state])
Ajeet Shah
  • 18,551
  • 8
  • 57
  • 87
0

You have mixed up state between functional component and class component. Clear concept is Functional Component does not have any state but it has useState hooks. for example:

const [state, setState] = useState({count: 0});

Though you used state for userState but here state is just a variable. You could have use like below:

const [counter, setCounter] = useState({count: 0});

On the other hand, for class component you have to use state that is like

constructor(props){
   super(props);
   this.state = {count: 0}
}

Where you can set the state object like

this.setState(prevState => {
    return {count: prevState.count+1}
});

Please the below two example for Functional Component and Class Component

Functional Component

import React, {useEffect, useState} from "react";

export default function Example() {

    const [state, setState] = useState({count: 0});

    const handleCount = () => {
        console.log(state); // prints {count: 0}
        setState({count: state.count+1});
        console.log(state); // prints {count: 1}
    };

    useEffect(() => {
        console.log('has changed.. ' + state.count)
    }, [state]);

    return (
        <div>
            <button onClick={() => handleCount()}>
                Click {state.count}
            </button>
        </div>
    );
}

Class Component

import React from "react";

export default class Example extends React.Component{
    constructor(props){
        super(props);
        this.state = {count: 0}
    }

    handleCount = () => {
        console.log(this.state); // prints {count: 0}
        this.setState(prevState => {
            return {count: prevState.count+1}
        });
        console.log(this.state); // prints {count: 1}
    };

    render() {
        return (
            <div>
                <button onClick={() => this.handleCount()}>
                    Click {this.state.count}
                </button>
            </div>
        );
    }
}
Khabir
  • 5,370
  • 1
  • 21
  • 33