adobe / react-spectrum

A collection of libraries and tools that help you build adaptive, accessible, and robust user experiences.
https://react-spectrum.adobe.com
Apache License 2.0
12.9k stars 1.12k forks source link

ListBox does not refresh ListData using remove/append/... #1064

Closed tomsontom closed 2 years ago

tomsontom commented 4 years ago

๐Ÿ› Bug Report

Change the ListData created through useListData() with APIs like remove/append/... does not refresh the visuals

๐Ÿค” Expected Behavior

Modifying the data list refreshes the List rendered in the browser window

๐Ÿ˜ฏ Current Behavior

List is rerendered until the container size changes (eg by resizing the window).

๐Ÿ’ Possible Solution

๐Ÿ”ฆ Context

I encountered this while looking into #977 and I guess this could also be the reason old data gets fed into useOptions.

๐Ÿ’ป Code Sample

import React, { useState } from 'react';
import {useListData} from '@react-stately/data'
import { Provider, defaultTheme, Button, Flex, ListBox, Item, Text } from '@adobe/react-spectrum';
import './App.css';

function App() {
  const options1 = [
    { id: 1, name: 'Aardvark', description: 'Aardvark Description' },
    { id: 2, name: 'Cat', description: 'Cat Description' },
    { id: 3, name: 'Dog', description: 'Dog Description' },
    { id: 4, name: 'Kangaroo', description: 'Kangaroo Description' },
    { id: 5, name: 'Koala', description: 'Koala Description' }
  ];
  const options2 = [
    { id: 6, name: 'Penguin', description: 'Penguin Description' },
    { id: 7, name: 'Snake', description: 'Snake Description' },
    { id: 8, name: 'Turtle', description: 'Turtle Description' },
    { id: 9, name: 'Wombat', description: 'Wombat Description' }
  ];

  let list = useListData(
    {
      initialItems: options1,
      getKey: (item) => "item" + item.id
    }
  )

  const clear = () => {
    const keyList = list.items.map(item => "item" + item.id)
    keyList.forEach( key => list.remove(key) )
  }

  const changeOptions = () => {
    clear()
    options2.forEach( val => list.append(val) )
  }

  return (
    <Provider theme={defaultTheme}>
      <Flex direction="column" rowGap={10}>
        <ListBox items={list.items}>{(item) => (
          <Item key={'item' + item.id} textValue={item.name}>
            <Text>{item.name}</Text>
            <Text slot="description">{item.description}</Text>
          </Item>)}
        </ListBox>
        <Button variant="cta" onPress={clear}>Clear</Button>
        <Button variant="cta" onPress={changeOptions}>Change options</Button>
      </Flex>
    </Provider>
  );
}

export default App;

๐ŸŒ Your Environment

Software Version(s)
react-spectrum 3.3.0
Browser
Operating System

๐Ÿงข Your Company/Team

๐Ÿ•ท Tracking Issue (optional)

tomsontom commented 4 years ago

I'm unable to reproduce this problem when I just copy it to the storybook -so to reproduce you really need to boostrap a react app and put the code in there.

LFDanLu commented 4 years ago

@tomsontom Just wanna clarify, this happens for you after you do https://github.com/adobe/react-spectrum/issues/977#issuecomment-690299692 correct? I noticed that the issue in https://github.com/adobe/react-spectrum/issues/977 actually goes away for me when I removed the wrapping <React.StrictMode> that @christian-baumann has in the sample app so do you happen to have the same wrapping <React.StrictMode> in your app? If so, does the above refresh issue happen when you remove it?

Not saying the fix is to remove strict mode, just wanna make sure what the reproduction steps are here.

tomsontom commented 4 years ago

this is right - if i remove the <React.StrictMode> things start working

devongovett commented 4 years ago

See also #779

LFDanLu commented 2 years ago

Closing in favor of the umbrella strict mode issue https://github.com/adobe/react-spectrum/issues/779