Package Exports
- react-select-async-paginate
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (react-select-async-paginate) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
react-select-async-paginate
Wrapper above react-select that supports pagination on menu scroll.
Sandbox examples
- Simple
- Multi
- Creatable
- Creatable with adding new options
- Initial options
- Autoload
- Debounce
- Request by page number
- Customization check of the need of load options
- Grouped options
- Custom select base
- Manual control of input value and menu opening
Versions
| react-select | react-select-async-paginate |
|---|---|
| 3.x | ^0.3.2 |
| 2.x | 0.3.x, 0.2.x |
| 1.x | 0.1.x |
Installation
npm install react-select react-select-async-paginateor
yarn add react-select react-select-async-paginateUsage
AsyncPaginate is an alternative of Async but supports loading page by page. It is wrapper above default react-select thus it accepts all props of default Select except isLoading. And there are some new props:
loadOptions
Required. Async function that take next arguments:
- Current value of search input.
- Loaded options for current search.
- Collected additional data e.g. current page number etc. For first load it is
additionalfrom props, for next isadditionalfrom previous response for current search.nullby default.
It should return next object:
{
options: Array,
hasMore: boolean,
additional?: any,
}It similar to loadOptions from Select.Async but there is some differences:
- Loaded options as 2nd argument.
- Additional data as 3nd argument.
- Not supports callback.
- Should return
hasMorefor detect end of options list for current search.
debounceTimeout
Not required. Number. Debounce timeout for loadOptions calls. 0 by default.
additional
Not required. Default additional for first request for every search.
shouldLoadMore
Not required. Function. By default new options will load only after scroll menu to bottom. Arguments:
- scrollHeight
- clientHeight
- scrollTop
Should return boolean.
reduceOptions
Not required. Function. By default new loaded options are concat with previous. Arguments:
- previous options
- loaded options
- next additional
Should return new options.
cacheUniq
Not required. Can take any value. When this prop changed, AsyncPaginate cleans all cached options.
loadOptionsOnMenuOpen
Not required. Boolean. If false options will not load on menu opening.
selectRef
Ref for take react-select instance.
SelectComponent
Not required. React component that will be used instead of SelectBase from react-select.
Example
offset way
import AsyncPaginate from 'react-select-async-paginate';
...
/*
* assuming the API returns something like this:
* const json = {
* results: [
* {
* value: 1,
* label: 'Audi',
* },
* {
* value: 2,
* label: 'Mercedes',
* },
* {
* value: 3,
* label: 'BMW',
* },
* ],
* has_more: true,
* };
*/
async function loadOptions(search, loadedOptions) {
const response = await fetch(`/awesome-api-url/?search=${search}&offset=${loadedOptions.length}`);
const responseJSON = await response.json();
return {
options: responseJSON.results,
hasMore: responseJSON.has_more,
};
}
<AsyncPaginate
value={value}
loadOptions={loadOptions}
onChange={setValue}
/>page way
import AsyncPaginate from 'react-select-async-paginate';
...
async function loadOptions(search, loadedOptions, { page }) {
const response = await fetch(`/awesome-api-url/?search=${search}&page=${page}`);
const responseJSON = await response.json();
return {
options: responseJSON.results,
hasMore: responseJSON.has_more,
additional: {
page: page + 1,
},
};
}
<AsyncPaginate
value={value}
loadOptions={loadOptions}
onChange={setValue}
additional={{
page: 1,
}}
/>Grouped options
You can use reduceGroupedOptions util to group options by label key.
import AsyncPaginate, { reduceGroupedOptions } from 'react-select-async-paginate';
/*
* assuming the API returns something like this:
* const json = {
* options: [
* label: 'Cars',
* options: [
* {
* value: 1,
* label: 'Audi',
* },
* {
* value: 2,
* label: 'Mercedes',
* },
* {
* value: 3,
* label: 'BMW',
* },
* ]
* ],
* hasMore: true,
* };
*/
...
<AsyncPaginate
{...otherProps}
reduceOptions={reduceGroupedOptions}
/>Manual control of input value and menu opening
You can use AsyncPaginateBase component.
import React, { useState } from 'react';
import { AsyncPaginateBase } from 'react-select-async-paginate';
...
async function loadOptions(search, loadedOptions) {
const response = await fetch(`/awesome-api-url/?search=${search}&offset=${loadedOptions.length}`);
const responseJSON = await response.json();
return {
options: responseJSON.results,
hasMore: responseJSON.has_more,
};
}
const MyWrapper = ({
value,
onChange,
}) => {
const [inputValue, onInputChange] = useState('');
const [menuIsOpen, setMenuIsOpen] = useState(false);
const onMenuOpen = () => {
setMenuIsOpen(true);
};
const onMenuClose = () => {
setMenuIsOpen(false);
};
return (
<AsyncPaginate
value={value}
loadOptions={loadOptions}
onChange={onChange}
inputValue={inputValue}
onInputChange={onInputChange}
menuIsOpen={menuIsOpen}
onMenuOpen={onMenuOpen}
onMenuClose={onMenuClose}
/>
);
};Replacing Components
Usage of replacing components is similar with react-select, but there is one difference. If you redefine MenuList you should wrap it with wrapMenuList for workaround of some internal bugs of react-select.
import AsyncPaginate, { wrapMenuList } from 'react-select-async-paginate';
...
const MenuList = wrapMenuList(CustomMenuList);
<AsyncPaginate
{...otherProps}
components={{
...otherComponents,
MenuList,
}}
/>