Passing object as an argument to useState( ) in Functional React Component

I am learning react hooks using reactjs.org.
I came across this statement which says that
Unlike with classes, the state doesn’t have to be an object. In the component below, i am trying to pass an object to useState

import React, {useState} from 'react';
import ReactDOM from 'react-dom';

function App(){
  let [state, setState] = useState({count: 1});
  function changeCounter(e){
      const targetClass = e.target.className;
      if(targetClass === 'increase'){
          if(state.count < 10){
              setState(state.count++);
          }
          
      }
      else if(targetClass === 'reduce'){
          if(state.count > 0){
              setState(state.count--);  
          }
          
  }
}
  let myApp = 
  <React.Fragment>
      <p> {state.count} </p>
       <button className = 'increase' onClick = {changeCounter}>
         +
      </button>
      <button className = 'reduce' onClick = {changeCounter}>
         -
      </button>
  </React.Fragment>
  return myApp;
}

ReactDOM.render(<App />, document.getElementById('root'));

Unfortunately the code doesn’t work. When i click the button, the p element disappears. When i pass an integer literal instead to useState, it works fine. Can someone explain what is happening?
You can check the code on Scrimba

You’re a. trying (and failing) to mutate the state value, and b. the state is an object. I’m unsure why you’re passing an object here as it just complicates things, but you’re literally trying to convert an object to a number: you are setting the state to a number.

Edit: useState is much simpler than the class API’s setState method. You seem to be thinking it does more than it does, that it’s as complex as setState.

  1. you give useState an initial value
  2. it returns a two-element array.
  3. first element is the current value (will be same as the value you put into useState at first).
  4. second element is a function that sets the value of the state. As in you give it a value, any value, that’s now the new current state.
  5. If you change the state (ie run that function), the component rerenders (just means the component function runs again).
  6. When it rerenders, the value that goes into useState is now the one you set in step 4.

I think it might be more understandable if you named these variables appropriately.

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

It seems to me that you are trying to manipulate a value called count in the state, so that’s what you should do here.

What it seems like you are trying to do is emulate setState(), where you pass in the entire state as an object each time you need to make a change to a value in the state. You don’t need to do that with useState, it allows you to directly change just one value in the state.

The value can be a namber, string, array, object, etc… You just need to make sure that you pass that same type of value into the setter function.

@DanCouper and @bbsmooth Thanks for your response. I am still learning React Hooks. I am passing an object because according to React Hooks Documentation, instead of using many state variables like

  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

You can pass an object because "State variables can hold objects and arrays just fine, so you can still group related data together". I am just trying to figure out how to update a state variable in case i decide to pass an object to useState rather than defining many state variables as above.

Yep, you can definitely do that. The thing to remember is that what you pass to the setter will completely overwrite whatever is currently stored for that value. So if you are storing an object, then you need to pass an object into the setter (and it needs to contain all of the information you want in that object).

In your initial code, you were doing

setState(state.count++);

That’s a number, not an object. The state variable is an object (at least that’s what you set it to as the default) and so that’s what you need to pass into the setter if you want to be consistent. When you passed a number into setState it changed state to a number instead of an object and thus your <p> tag did not update properly because it was expecting an object.

2 Likes