#How to turn props into state?

1 messages · Page 1 of 1 (latest)

lofty sparrow
#

I have this component:

"use client";

import { Player } from "@prisma/client"
import { io } from "socket.io-client";
import { useState } from "react";

export default function Leaderboard({ initialPlayers }: { initialPlayers: Player[] }) {

  const [players, setPlayers] = useState(initialPlayers);

  var socket: any;
  socket = io("http://localhost:3001");

  console.log(`players (state): `, players)

  return (
      <div className="w-full h-1/2 bg-red-500">
        {players
          .sort((a, b) => b.points - a.points)
          .map((player) => {
            return (
              <div key={player.id}>
                {player.username} ({player.points})
              </div>
            );
          })}
      </div>
  );
}

I would expect the following things to happen when the component is used:

  1. props initialPlayers is passed into the component from its parent
  2. players in state gets initialized with initialPlayers array from props
  3. code renders a list of players

However, the state players is undefined at the time of rendering. The error message I get it:

TypeError: Cannot read properties of undefined (reading 'sort')
proven currentBOT
#

Hi @lofty sparrow. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

The error message you're seeing suggests that players is undefined at the time of rendering. This could be because initialPlayers is undefined when passed as a prop to the Leaderboard component.

In your useState hook, you're initializing players with initialPlayers. If initialPlayers is undefined, then players will also be undefined.

const [players, setPlayers] = useState(initialPlayers);

To fix this, you could provide a default value for players in case initialPlayers is undefined. For example, you could initialize players as an empty array if initialPlayers is not provided:

const [players, setPlayers] = useState(initialPlayers || []);

This way, even if initialPlayers is undefined, players will be an empty array and you won't get a TypeError when you try to call sort on players.

Remember, the initial state passed to a useState is not expected to change after the initial render. This is mentioned in a comment from a Github issue (https://github.com/vercel/next.js/issues/54049) in the knowledge sources:

This is expected and not related to Next.js. The initial state passed to a useState is not expected to change after the initial render. Read more in the React docs: https://react.dev/reference/react/useState#parameters

This argument is ignored after the initial render.

So, if initialPlayers changes after the initial render of Leaderboard, those changes won't be reflected in players. If you want players to update when initialPlayers changes, you could use a useEffect hook to update players whenever initialPlayers changes:

useEffect(() => {
  setPlayers(initialPlayers || []);
}, [initialPlayers]);
#

This useEffect hook will run whenever initialPlayers changes, and will update players with the new value of initialPlayers.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: