DEV Community

Cover image for Using React useState Hook to Manage Object Props
Michael J. Larocca
Michael J. Larocca

Posted on • Originally published at selftaughttxg.com

Using React useState Hook to Manage Object Props

This week's article explores the powerful realm of the React useState hook! We create a player component, update specific object properties, and explain how to pass object props to child components!


TXG-84


Introduction

This article explores how to use the React useState hook to manage object props in a React component. We will create a Player component that accepts props as an argument and use the useState hook to create an object variable called player and a function called setPlayer to update the player variable.

We will then discuss how to handle object props by accessing and updating specific properties, as well as passing them to child components. Additionally, we'll create a Shoot Arrow button that decreases the arrow count and increases the score and disable the button when the arrow count reaches zero.

By the end of this article, you'll have a better understanding of how to manage object props in your React components using the useState hook.

Note: We will be focusing on learning React code, not CSS. However, feel free to clone the project or copy the CSS code.


The Player React component

We will create a React component named Player that accepts props as an argument.

In the Player React component, we are using the React useState hook to create an object variable called player and a function called setPlayer; the setPlayer function provides us with a way to update the player variable.

Then we will create key-value pairs, setting the passed-in props as values. We can use the JavaScript or operator || to set default values if props are not passed in when the component is used. (We will "hard-code" the Bow as a weapon since this is a simple comment that uses arrows šŸ¹.)

import React, { useState } from "react";

function Player(props) {
    const [player, setPlayer] = useState({
        name: props.name || "Player",
        score: props.score || 0,
        level: props.level || 1,
        weapon: "Bow",
        arrows: props.arrows || 20,
      });
Enter fullscreen mode Exit fullscreen mode

Adding the Player component

Now we can import the React Player component and add them to our App. We can set the starting values or simply add <Player />, which will use the default values we created in the player object.

import { useState } from 'react'
import './App.css'
import Player from './components/Player'

function App() {

  return (
    <>
      <Player name="Legolas" score={10} level={20} arrows={50} />
      <Player />
    </>
  )
}

export default App
Enter fullscreen mode Exit fullscreen mode

Cards 2


Managing Object Props

When working with React components that accept object props, it's important to ensure that all object properties are retained, even if you only want to update one or two of them.

To update a specific property of the object, we can use the spread operator to create a copy of the object's previous state first and then update the specific property we want to change. With this method, all other properties of the object are retained.


Shoot Arrows button

We will now create a button to shoot the arrows. We will decrease the arrow count by 1 for each arrow shot and increase the score by 10.

As mentioned earlier, we want to capture the player object's previous state first and then update the arrow and score values.

Using the setPlayer function, we pass in the player object's previous state (prevState **) as an argument. Then with an arrow function, to include the entire **player object, we use a JavaScript spread operator ... on the prevState.

With the previous state of the entire player object included, we can now update the arrows and score values as follows:

      function handleClick() {
        setPlayer(prevState => ({
          ...prevState,
          arrows: prevState.arrows - 1,
          score: prevState.score + 10
        }));
      }
Enter fullscreen mode Exit fullscreen mode

Return a player card

Finally, we return a player card utilizing props and a button that runs the handleClick function that shoots the remaining arrows.

We can disable the Shoot Arrow button by setting the disabled attribute to true when the arrow count reaches zero.

      return (
        <div className="player">
          <h1>{player.name}</h1>
          <div className="card-inner">
          <p>Score: <strong>{player.score}</strong></p>
          <p>Level: <strong>{player.level}</strong></p>
          <p>Weapon: <strong>{player.weapon}</strong></p>
          <p>Arrows: <strong>{player.arrows}</strong></p>
          </div>
          <button disabled={player.arrows === 0} onClick={handleClick}>Shoot Arrow</button>
        </div>
      );
Enter fullscreen mode Exit fullscreen mode

The completed Player component

import React, { useState } from "react";

function Player(props) {
    const [player, setPlayer] = useState({
        name: props.name || "Player",
        score: props.score || 0,
        level: props.level || 1,
        weapon: "Bow",
        arrows: props.arrows || 20,
      });

      function handleClick() {
        setPlayer(prevState => ({
          ...prevState,
          arrows: prevState.arrows - 1,
          score: prevState.score + 10
        }));
      }

      return (
        <div className="player">
          <h1>{player.name}</h1>
          <div className="card-inner">
          <p>Score: <strong>{player.score}</strong></p>
          <p>Level: <strong>{player.level}</strong></p>
          <p>Weapon: <strong>{player.weapon}</strong></p>
          <p>Arrows: <strong>{player.arrows}</strong></p>
          </div>
          <button disabled={player.arrows === 0} onClick={handleClick}>Shoot Arrow</button>
        </div>
      );
}

export default Player;
Enter fullscreen mode Exit fullscreen mode

The finished project

Here are the links to the finished project:
šŸ”— GitHub
šŸ”— Netlify


The React environment

If you would like to learn how to set up a local React development environment, I wrote the following two beginner-friendly articles:


Conclusion

Throughout this article, we've covered how to use the React useState hook to manage object props, update specific properties using the spread operator, and pass object props to child components.

Additionally, we've created a Shoot Arrows button using the useState hook to decrease the arrow count, increase the score, and disable the button when the arrow count reaches zero.

When working with object props in React, it's crucial to include the previous state of the whole object when updating its properties to ensure all properties are retained!

Congratulations on completing your journey into the realm of the React useState hook! Keep exploring, learning, and building with React using the knowledge you've gained!


Let's connect! I'm active on LinkedIn and Twitter.


Do you now understand how to update individual values in object props? Do you know other ways to update individual values in object props? Please share the article and comment!

Top comments (1)

Collapse
 
brense profile image
Rense Bakker

You can also use a reducer function for this, so you dont have to spread the current state manually for each setPlayer call:

const initialState = {
  name: 'Player',
  score: 0,
  level: 1,
  weapon: 'Bow',
  arrows: 20,
}

function playerReducer(currentState: typeof initialState, nextState: Partial<typeof initialState>){
  return { ...currentState, ...nextState }
}

function Player(props: Partial<typeof initialState>){
  const combinedInitialState = useMemo(() => ({ ...initialState, ...props }), [props])
  const [player, setPlayer] = useReducer(playerReducer, combinedInitialState)

  const handleShootArrow = useCallback(() => {
    setPlayer({
      // we dont have to spread the whole player object here
      // because the reducer already does that for us
      arrows: player.arrows - 1,
      score: player.score + 10
    })
  }, [player])

  // ...
}
Enter fullscreen mode Exit fullscreen mode

You could also make the reducer more complex, for example you could do something like this:

function playerReducer(currentState: typeof initialState, action: { type: 'SHOOT_ARROW' }){
  switch(action.type){
    case 'SHOOT_ARROW':
      return {
        ...currentState,
        arrows: currentState.arrows - 1,
        score: currentState.score + 10
      }
  }
}
Enter fullscreen mode Exit fullscreen mode