DEV Community

Joseph Lynn
Joseph Lynn

Posted on

React hooks - working with state (objects)

How to declare initial state

To use the useState hook you will need to import it from React.

You can view the code sandbox for a more interactive way to follow and mess around with the code (recommended to fork and try out yourself): code sandbox

import React, {useState} from "react";
Enter fullscreen mode Exit fullscreen mode

To keep track of the state, we need to call the useState hook with an initial value. Since useState returns an array we are able to destructure the current state value and a function that lets you update the state.

Here's what that looks like.

// variable name is up to you (state)
// then name your function the variable name but with "set" as a prefix (setState)
const [state, setState] = useState({});
Enter fullscreen mode Exit fullscreen mode

Creating the component

Let's start building a basic component. Here we will create the initial state to a basic component.

// import React and the useState hook
import React, {useState} from "react";

// component function 
function SimpleObjectComponent() {
  // set the initial state (an object with the properties we want since we know that's what we want the user variable value to start as)
  const [user, setUser] = useState({
    id: 1,
    name: ""
  });
}

export default SimpleObjectComponent;
Enter fullscreen mode Exit fullscreen mode

Let's add a basic button to change the state and a spot in the DOM to see the state change.

  // JSX we want to return 
  return (
    // parent div to hold the button and h1
    <div className="App">
      {/* Get the value of user.name */}
      <h1>{user.name}</h1>
      {/* Call the handleNameChange function when the button is clicked */}
      <button onClick={handleNameChange}>Change name</button>
    </div>
  );
Enter fullscreen mode Exit fullscreen mode

This is all you will have for now:
alt text

Creating component functionality

You see we declared a function called "handleNameChange". That function doesn't exist yet. Lets create that.

  // delcare the function 
  function handleNameChange() {
    // create a variable that produces a new value so we can use that new value to update state 
    const updateItem = {
      // it's important to not mutate state directly, so here we are creating a copy of the current state using the spread syntax
      // you can also clone an object using Object.assign({}, user) (see below)
      ...user,
      // after we copy the state, we can add new properties and/or new values to the copied state
      name: "Joe"
    };
    // no we want to update the state with the new value we created 
    setUser(updateItem);

    // Object.assign method
    // create a copy of the user object 
    const updatedObject = Object.assign({}, user)
    // change the copied object property "name"
    updatedObject.name = "Joe"
    // set the new state 
    setUser(updatedObject)
  }
Enter fullscreen mode Exit fullscreen mode

Click the "Change name" button and you will see the state changed
alt text

This quick tutorial shows you how to setup basic state values using objects and how you can return a new object state value.

Thanks for reading!

Oldest comments (4)

Collapse
 
lexlohr profile image
Alex Lohr

Why don't you keep id and name separate, i.e.

const [id, setId] = useState(1)
const [name, setName] = useState('')
Enter fullscreen mode Exit fullscreen mode

This way, you don't even need to handleNameChange and your code suddenly becomes a lot simpler.

Collapse
 
joelynn profile image
Joseph Lynn

In this simple example that is definitely doable. I just wanted to show a simple way to handle state with objects. In a real application I would have a truly unique id (like using uuid) for each object, that way you can easily identify, sort and filter as the object would be more complex.

Collapse
 
lexlohr profile image
Alex Lohr

I think useReducer would be a better fit for more complex states than manual mangling objects. However, I would only use it if it truly reflects the actual complexity of the use case, which is not really broken down into less complex states.

Thread Thread
 
joelynn profile image
Joseph Lynn • Edited

I agree that useReducer would be beneficial for complex state. However we are adding a static object in this case. We are not mangling the object state, we are copying the current state and adding a new object (which is exactly what useReducer would do but based on an action). It would not work to have separate state for id and name in this case - as they work together and identify the object.