useListData

Manages state for an immutable list data structure, and provides convenience methods to update the data over time.

installyarn add react-stately
version3.33.0
usageimport {useListData} from 'react-stately'

Introduction#


React requires all data structures passed as props to be immutable. This enables them to be diffed correctly to determine what has changed since the last render. This can be challenging to accomplish from scratch in a performant way in JavaScript.

useListData helps manage an immutable list data structure, with helper methods to update the data in an efficient way. Since the data is stored in React state, calling these methods to update the data automatically causes the component to re-render accordingly.

In addition, useListData stores selection state for the list, based on unique item keys. This can be updated programmatically, and is automatically updated when items are removed from the list.

API#


useListData<T>( (options: ListOptions<T> )): ListData<T>

Options#


NameTypeDescription
initialItemsT[]Initial items in the list.
initialSelectedKeys'all'Iterable<Key>The keys for the initially selected items.
initialFilterTextstringThe initial text to filter the list by.
getKey( (item: T )) => KeyA function that returns a unique key for an item object.
filter( (item: T, , filterText: string )) => booleanA function that returns whether a item matches the current filter text.

Interface#


Properties

NameTypeDescription
itemsT[]The items in the list.
selectedKeysSelectionThe keys of the currently selected items in the list.
filterTextstringThe current filter text.

Methods

MethodDescription
setSelectedKeys( (keys: Selection )): voidSets the selected keys.
setFilterText( (filterText: string )): voidSets the filter text.
getItem( (key: Key )): TGets an item from the list by key.
insert( (index: number, , ...values: T[] )): voidInserts items into the list at the given index.
insertBefore( (key: Key, , ...values: T[] )): voidInserts items into the list before the item at the given key.
insertAfter( (key: Key, , ...values: T[] )): voidInserts items into the list after the item at the given key.
append( (...values: T[] )): voidAppends items to the list.
prepend( (...values: T[] )): voidPrepends items to the list.
remove( (...keys: Key[] )): voidRemoves items from the list by their keys.
removeSelectedItems(): void

Removes all items from the list that are currently in the set of selected items.

move( (key: Key, , toIndex: number )): voidMoves an item within the list.
moveBefore( (key: Key, , keys: Iterable<Key> )): voidMoves one or more items before a given key.
moveAfter( (key: Key, , keys: Iterable<Key> )): voidMoves one or more items after a given key.
update( (key: Key, , newValue: T )): voidUpdates an item in the list.

Example#


To construct a list, pass an initial set of items along with a function to get a key for each item. You can use the state returned by useListData to render a collection component.

This example renders a ListBox using the items managed by useListData. It uses the name property of each item as the unique key for that item, and the items property as the children. In addition, it manages the selection state for the listbox, which will automatically be updated when items are removed from the tree.

let list = useListData({
  initialItems: [
    {name: 'Aardvark'},
    {name: 'Kangaroo'},
    {name: 'Snake'}
  ],
  initialSelectedKeys: ['Kangaroo'],
  getKey: item => item.name
});

<ListBox
  items={list.items}
  selectedKeys={list.selectedKeys}
  onSelectionChange={list.setSelectedKeys}>
  {item => <Item key={item.name}>{item.name}</Item>}
</ListBox>
let list = useListData({
  initialItems: [
    {name: 'Aardvark'},
    {name: 'Kangaroo'},
    {name: 'Snake'}
  ],
  initialSelectedKeys: ['Kangaroo'],
  getKey: item => item.name
});

<ListBox
  items={list.items}
  selectedKeys={list.selectedKeys}
  onSelectionChange={list.setSelectedKeys}>
  {item => <Item key={item.name}>{item.name}</Item>}
</ListBox>
let list = useListData({
  initialItems: [
    { name: 'Aardvark' },
    { name: 'Kangaroo' },
    { name: 'Snake' }
  ],
  initialSelectedKeys: [
    'Kangaroo'
  ],
  getKey: (item) =>
    item.name
});

<ListBox
  items={list.items}
  selectedKeys={list
    .selectedKeys}
  onSelectionChange={list
    .setSelectedKeys}
>
  {(item) => (
    <Item
      key={item.name}
    >
      {item.name}
    </Item>
  )}
</ListBox>

Inserting items#

To insert a new item into the list, use the insert method or one of the other convenience methods. Each of these methods also accepts multiple items, so you can insert multiple items at once.

// Insert an item after the first one
list.insert(1, {name: 'Horse'});

// Insert multiple items
list.insert(1, {name: 'Horse'}, {name: 'Giraffe'});
// Insert an item after the first one
list.insert(1, {name: 'Horse'});

// Insert multiple items
list.insert(1, {name: 'Horse'}, {name: 'Giraffe'});
// Insert an item after the first one
list.insert(1, {
  name: 'Horse'
});

// Insert multiple items
list.insert(1, {
  name: 'Horse'
}, { name: 'Giraffe' });
// Insert an item before another item
list.insertBefore('Kangaroo', {name: 'Horse'});

// Insert multiple items before another item
list.insertBefore('Kangaroo', {name: 'Horse'}, {name: 'Giraffe'});
// Insert an item before another item
list.insertBefore('Kangaroo', { name: 'Horse' });

// Insert multiple items before another item
list.insertBefore('Kangaroo', { name: 'Horse' }, {
  name: 'Giraffe'
});
// Insert an item before another item
list.insertBefore(
  'Kangaroo',
  { name: 'Horse' }
);

// Insert multiple items before another item
list.insertBefore(
  'Kangaroo',
  { name: 'Horse' },
  { name: 'Giraffe' }
);
// Insert an item after another item
list.insertAfter('Kangaroo', {name: 'Horse'});

// Insert multiple items after another item
list.insertAfter('Kangaroo', {name: 'Horse'}, {name: 'Giraffe'});
// Insert an item after another item
list.insertAfter('Kangaroo', { name: 'Horse' });

// Insert multiple items after another item
list.insertAfter('Kangaroo', { name: 'Horse' }, {
  name: 'Giraffe'
});
// Insert an item after another item
list.insertAfter(
  'Kangaroo',
  { name: 'Horse' }
);

// Insert multiple items after another item
list.insertAfter(
  'Kangaroo',
  { name: 'Horse' },
  { name: 'Giraffe' }
);
// Append an item
list.append({name: 'Horse'});

// Append multiple items
list.append({name: 'Horse'}, {name: 'Giraffe'});
// Append an item
list.append({name: 'Horse'});

// Append multiple items
list.append({name: 'Horse'}, {name: 'Giraffe'});
// Append an item
list.append({
  name: 'Horse'
});

// Append multiple items
list.append({
  name: 'Horse'
}, { name: 'Giraffe' });
// Prepend an item
list.prepend({name: 'Horse'});

// Prepend multiple items
list.prepend({name: 'Horse'}, {name: 'Giraffe'});
// Prepend an item
list.prepend({name: 'Horse'});

// Prepend multiple items
list.prepend({name: 'Horse'}, {name: 'Giraffe'});
// Prepend an item
list.prepend({
  name: 'Horse'
});

// Prepend multiple items
list.prepend({
  name: 'Horse'
}, { name: 'Giraffe' });

Removing items#

// Remove an item
list.remove('Kangaroo');

// Remove multiple items
list.remove('Kangaroo', 'Snake');
// Remove an item
list.remove('Kangaroo');

// Remove multiple items
list.remove('Kangaroo', 'Snake');
// Remove an item
list.remove('Kangaroo');

// Remove multiple items
list.remove(
  'Kangaroo',
  'Snake'
);
// Remove all selected items
list.removeSelectedItems();
// Remove all selected items
list.removeSelectedItems();
// Remove all selected items
list
  .removeSelectedItems();

Moving items#

list.move('Snake', 0);
list.move('Snake', 0);
list.move('Snake', 0);

Updating items#

list.update('Snake', {name: 'Rattle Snake'});
list.update('Snake', {name: 'Rattle Snake'});
list.update('Snake', {
  name: 'Rattle Snake'
});