Home > Software engineering >  Unfocusing dropdown menu sets its state as undefined
Unfocusing dropdown menu sets its state as undefined

Time:10-30

I'm making a dropdown menu that allows user to set a state and then see the page corresponding to chosen values.

I isolated my code to fully reproduce the issue both in text and in this [CodeSandbox]

Desired baheviour - Open menu, set state using its componets, close menu and keep the state.

Current behaviour - Open menu, set state using its components, close menu and state is set to undefined.

I track the changes to the state in the console and can clearly see that adding items to filter is seen in the updated state every time. However when I close the menu the state changes to undefined and the state is unsuable for my needs.

How do I change the code so the state persists when the menu is closed?

Thanks in advance for your time!

import React from "react";
import { default as ReactSelect } from "react-select";
import { components } from "react-select";

export default function BettingDeck(props) {
  const sportsOptions = [
    { value: "soccer", label: "Soccer" },
    { value: "dota", label: "Dota 2" },
    { value: "tennis", label: "Tennis" },
    { value: "csgo", label: "CS:GO" }
  ];

  const Option = (props) => {
    return (
      <div>
        <components.Option {...props}>
          <input
            type="checkbox"
            checked={props.isSelected}
            onChange={() => null}
          />{" "}
          <label>{props.label}</label>
        </components.Option>
      </div>
    );
  };

  const [sportsSelectorState, setSportsSelectorState] = React.useState({
    optionSelected: [],
    isFocused: true
  });

  function handleChange(selected) {
    setSportsSelectorState(() => {
      return { optionSelected: selected };
    });
  }

  console.log(sportsSelectorState.optionSelected);


  return (
    <>
      <div className="betting-deck-container">
        <div className="betting-deck-head-container">
          <div className="betting-deck-title">Betting Deck</div>

          {/* <SportsSelector /> */}
          <span
            
            data-toggle="popover"
            data-trigger="focus"
            data-content="Please selecet account(s)"
            onBlur={() => {
              setSportsSelectorState({ isFocused: false });
            }}
            onFocus={() => {
              setSportsSelectorState({ isFocused: true });
            }}
            style={
              sportsSelectorState.isFocused ? { zIndex: 1 } : { zIndex: 0 }
            }
          >
            <ReactSelect
              options={sportsOptions}
              isMulti
              closeMenuOnSelect={false}
              hideSelectedOptions={false}
              components={{
                Option
              }}
              onChange={handleChange}
              allowSelectAll={true}
              value={sportsSelectorState.optionSelected}
              placeholder="Select sports to filter"
              menuPortalTarget={document.body}
              classNamePrefix="mySelect"
            />
          </span>
        </div>
      </div>
    </>);}

CodePudding user response:

Every time you set the state, you overwrite it with a new object.

So this:

setSportsSelectorState(() => {
  return { optionSelected: selected };
});

practically removes isFocused from the object.

And this removes optionSelected:

setSportsSelectorState({ isFocused: true });

So to always preserve the entire object, spread the previous state (object) into the new and only overwrite the relevant property:

// The parameter in the callback function (prev)
// always holds the previous state, or should
// I say the state as it currently is
// before you change it.

setSportsSelectorState((prev) => {
  return { ...prev, isFocused: true };
});

// or

setSportsSelectorState((prev) => {
  return { ...prev, optionSelected: selected };
});
  • Related