React-select: Options doesn't re-render when updating a grouped options

Created on 14 Oct 2020  路  2Comments  路  Source: JedWatson/react-select

Hi, updating the grouped options doesn't re-render the options but works fine for non-grouped options. It only gets re-rendered after the selection.

Here's a sample code, it increments the option when the menu opens or when it scrolls down.

https://codesandbox.io/s/react-select-v3-sandbox-forked-mfj07?fontsize=14&hidenavigation=1&theme=dark

const Example = () => {
  const [counter, setCounter] = React.useState(0);
  const [options, setOptions] = React.useState([
    {
      label: "select1",
      options: [
        {
          label: "item1",
          value: 1
        }
      ]
    }
  ]);

  const incrementOptions = () => {
    setCounter(counter + 1);
    options[0].options = [
      ...options[0].options,
      { label: "item" + counter, value: counter }
    ];
    setOptions(options);
  };

  const handleScrollBottom = () => {
    incrementOptions();
  };

  const handleMenuOpen = () => {
    incrementOptions();
  };

  return (
    <div className="App">
      <Select
        options={options}
        onMenuScrollToBottom={handleScrollBottom}
        onMenuOpen={handleMenuOpen}
      />
    </div>
  );
};
issubug-confirmed

All 2 comments

Hi @Keinstah, this keeps the same reference options[0].options so if you refresh that, group options would re-render as well

Try this:

  const incrementOptions = () => {
    setCounter(counter + 1);
    const newOptions = [
      {
        ...options[0],
        options: [
          ...options[0].options,
          { label: "item" + counter, value: counter }
        ]
      }
    ]
    setOptions(newOptions);
  };

@s4djan Thank you for spotting that. It's also worth mentioning that hooks are async so the use of counter is not guaranteed to be any particular value. I created a working sandbox and added another group to demonstrate this working with multiple groups.

Working Demo: codesandbox

```js
const incrementOptions = () => {
// Save new counter variable to be used syncronously and to be set to state
const newCounter = counter + 1;

// Deconstruct array to spread rest operator after we have group with new option
const [group1, ...otherGroups] = options;
const newGroupOption = { label: `item${newCounter}`, value: newCounter };

// Create new group1 as clone of group1, but overwrite
// options with all existing plus new option
const newGroup1 = {
  ...group1,
  options: [...group1.options, newGroupOption]
};

// Update state
setCounter(newCounter);
setOptions([newGroup1, ...otherGroups]);

console.log(`Added "${newGroupOption.label}" to group1`);

};
```

I appreciate your help on this. I'll mark this closed as it appears to be working as intended, but if you have any further questions @Keinstah please feel free to reply and we can re-open this if necessary.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pashap picture pashap  路  3Comments

MalcolmDwyer picture MalcolmDwyer  路  3Comments

ericj17 picture ericj17  路  3Comments

mbonaci picture mbonaci  路  3Comments

x-yuri picture x-yuri  路  3Comments