useListData
Manages state for an immutable list data structure, and provides convenience methods to update the data over time.
install | yarn add @react-stately/data |
---|---|
version | 3.4.7 |
usage | import {useListData} from '@react-stately/data' |
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#
Name | Type | Description |
initialItems | T[] | Initial items in the list. |
initialSelectedKeys | 'all' | Iterable<Key> | The keys for the initially selected items. |
initialFilterText | string | The initial text to filter the list by. |
getKey | (
(item: T
)) => Key | A function that returns a unique key for an item object. |
filter | (
(item: T,
, filterText: string
)) => boolean | A function that returns whether a item matches the current filter text. |
Interface#
Properties
Name | Type | Description |
items | T[] | The items in the list. |
selectedKeys | Selection | The keys of the currently selected items in the list. |
filterText | string | The current filter text. |
Methods
Method | Description |
setSelectedKeys(
(keys: Selection
)): void | Sets the selected keys. |
setFilterText(
(filterText: string
)): void | Sets the filter text. |
getItem(
(key: Key
)): T | Gets an item from the list by key. |
insert(
(index: number,
, ...values: T[]
)): void | Inserts items into the list at the given index. |
insertBefore(
(key: Key,
, ...values: T[]
)): void | Inserts items into the list before the item at the given key. |
insertAfter(
(key: Key,
, ...values: T[]
)): void | Inserts items into the list after the item at the given key. |
append(
(...values: T[]
)): void | Appends items to the list. |
prepend(
(...values: T[]
)): void | Prepends items to the list. |
remove(
(...keys: Key[]
)): void | Removes 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
)): void | Moves an item within the list. |
moveBefore(
(key: Key,
, keys: Key[]
)): void | Moves one or more items before a given key. |
moveAfter(
(key: Key,
, keys: Key[]
)): void | Moves one or more items after a given key. |
update(
(key: Key,
, newValue: T
)): void | Updates 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.insertAfter('Kangaroo', {name: 'Horse'});
// Insert multiple items before another item
list.insertAfter('Kangaroo', {name: 'Horse'}, {name: 'Giraffe'});
// Insert an item before another item
list.insertAfter('Kangaroo', { name: 'Horse' });
// Insert multiple items before another item
list.insertAfter('Kangaroo', { name: 'Horse' }, {
name: 'Giraffe'
});
// Insert an item before another item
list.insertAfter(
'Kangaroo',
{ name: 'Horse' }
);
// Insert multiple items before 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'
});
// 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'
});