Search code examples
javascriptarraysreactjsuse-effectuse-state

I'm having trouble updating state with a select menu


As the title suggests, I'm having issues updating state with a select menu. I'm not sure if the trouble is coming from the fact I'm trying to update it from multiple sources?

getSurvivorPerks fetches an array of objects. On page load a random 4 are selected to be displayed, and these four are randomized on each handlesubmit. I would like to be able to manually select the individual perks for perk1, 2, etc with a select menu. As of now, this just results in perk1 getting set to Null. The data does display appropriately in the select menu.

export default function SurvivorRandomizer() {
  const [survivorPerk1, setSurvivorPerk1] = useState({});
  const [survivorPerk2, setSurvivorPerk2] = useState({});
  const [survivorPerk3, setSurvivorPerk3] = useState({});
  const [survivorPerk4, setSurvivorPerk4] = useState({});
  const [perkList, setPerkList] = useState([]);
  const [loading, setLoading] = useState(true);
  const { user } = useUser();

  useEffect(() => {
    const fetchData = async () => {
      const data = await getSurvivorPerks();
      let perks = randomPerks(data);
      setPerkList(data);
      setSurvivorPerk1(perks[0]);
      setSurvivorPerk2(perks[1]);
      setSurvivorPerk3(perks[2]);
      setSurvivorPerk4(perks[3]);
      setLoading(false);
    };
    fetchData();
  }, []);

  const handleSubmit = () => {
    let perks = randomPerks(perkList);
    setSurvivorPerk1(perks[0]);
    setSurvivorPerk2(perks[1]);
    setSurvivorPerk3(perks[2]);
    setSurvivorPerk4(perks[3]);
  };

 if (loading) return <h1>loading...</h1>;
  return (
    <>
      <div className="perk-row-1">
        <div className="perk-card">
          <PerkCard {...survivorPerk1} />
          <select value={perkList.perk} onChange={(e) => setSurvivorPerk1(e.target.value)}>
            <option>Select...</option>
            {perkList.map((perk) => (
              <option key={uuid()} value={perk}>
                {perk.name}
              </option>
            ))}
          </select>
        </div>

Solution

  • The issue here (had my blinders on) is that the value cannot be an object.

     const handlePerkSelect = async (perk, id) => {
        let setPerk = await getSurvivorPerkById(id);
        perk(setPerk);
      };
    
    -------------
              <select onChange={(e) => handlePerkSelect(setSurvivorPerk1, e.target.value)}>
                <option>Select...</option>
                {perkList.map((perk) => (
                  <option key={uuid()} value={perk.ID}>
                    {perk.name}
                  </option>
                ))}
              </select>
    

    This was my solution. There's definitely a better way to do it that doesn't involve making more fetch requests, and I'll likely refactor, but on the off chance this helps someone, I figured I'd share what the issue was.