mgP*_*ePe 4 reactjs react-select
我想设置一个组件react-select来处理服务器端数据并进行服务器端过滤,但由于多种原因它不起作用。
您能解释一下并显示工作代码吗?
让我们首先表达看起来react-select很棒但没有很清楚记录的观点。就我个人而言,我并不喜欢该文档,原因如下:
CTRL+F,一切都会亮起来。很没用因此,我将尝试通过提供逐步的步骤、代码和问题+解决方案来为本文提供一些帮助。
const [options, setOptions] = useState([
{ id: 'b72a1060-a472-4355-87d4-4c82a257b8b8', name: 'illy' },
{ id: 'c166c9c8-a245-48f8-abf0-0fa8e8b934d2', name: 'Whiskas' },
{ id: 'cb612d76-a59e-4fba-8085-c9682ba2818c', name: 'KitKat' },
]);
<Select
defaultValue={options[0]}
isClearable
options={options}
getOptionLabel={(option) => option.name}
getOptionValue={(option) => option.id}
/>
Run Code Online (Sandbox Code Playgroud)
它通常有效,但您会注意到,如果我键入的字母d与任何地方的任何选项都不匹配,选项会保留,而不是显示“无选项”。
我会忽略这个问题,因为它很小而且似乎无法解决。
到目前为止一切顺利,我们可以忍受这个小问题。
我们现在的目标是简单地将静态数据与服务器加载的数据交换。嗯,这能有多难呢?
我们首先需要交换<Select/>为<AsyncSelect/>. 现在我们如何加载数据?
所以查看文档有多种加载数据的方法:
defaultOptions: The default set of options to show before the user starts searching. When set to true, the results for loadOptions('') will be autoloaded.
and
loadOptions: Function that returns a promise, which is the set of options to be used once the promise resolves.
Run Code Online (Sandbox Code Playgroud)
仔细阅读它,您会明白defaultOptions需要是一个布尔值 true 并且loadOptions应该有一个返回选择的函数:
<AsyncSelect
defaultValue={options[0]}
isClearable
getOptionLabel={(option) => option.name}
getOptionValue={(option) => option.id}
defaultOptions
loadOptions={loadData}
/>
Run Code Online (Sandbox Code Playgroud)
看起来很棒,我们已经加载了远程数据。但我们现在想预设默认值。我们必须通过 来匹配它Id,而不是选择第一个。我们的第一个问题来了:
问题:你不能
defaultValue从一开始就设置 ,因为你没有数据可以匹配它。如果您尝试设置defaultValue组件加载后,则它不起作用。
为了解决这个问题,我们需要提前加载数据,匹配我们拥有的初始值,一旦我们拥有这两个值,我们就可以初始化组件。有点难看,但考虑到限制,这是我能弄清楚的唯一方法:
const [data, setData] = useState(null);
const [initialObject, setInitialObject] = useState(null);
const getInitial = async () => {
// make your request, once you receive data:
// Set initial object
const init= res.data.find((item)=>item.id=ourInitialId);
setInitialObject(init);
// Set data so component initializes
setData(res.data);
};
useEffect(() => {
getInitial();
}, []);
return (
<>
{data!== null && initialObject !== null ? (
<AsyncSelect
isClearable
getOptionLabel={(option) => option.name}
getOptionValue={(option) => option.id}
defaultValue={initialObject}
defaultOptions={options}
// loadOptions={loadData} // we don't need this anymore
/>
) : null}
</>
)
Run Code Online (Sandbox Code Playgroud)
由于我们自己加载数据,所以不需要,loadOptions所以我们将其取出。到目前为止,一切都很好。
所以现在我们需要一个可用于获取数据的回调。我们回顾一下文档:
onChange: (no description, from section "StateManager Props")
onInputChange: Same behaviour as for Select
Run Code Online (Sandbox Code Playgroud)
所以我们听文档并返回“选择道具”部分找到:
onInputChange: Handle change events on the input`
Run Code Online (Sandbox Code Playgroud)
富有洞察力...不是。
我们看到一个函数类型定义似乎有一些线索:
我想,该字符串必须是我的文本/查询。显然,变化的类型有所下降。我们出发——
const [data, setData] = useState(null);
const [initialObject, setInitialObject] = useState(null);
const getInitial = async () => {
// make your request, once you receive data:
// Set initial object
const init= res.data.find((item)=>item.id=ourInitialId);
setInitialObject(init);
// Set data so component initializes
setData(res.data);
};
useEffect(() => {
getInitial();
}, []);
const loadData = async (query) => {
// fetch your data, using `query`
return res.data;
};
return (
<>
{data!== null && initialObject !== null ? (
<AsyncSelect
isClearable
getOptionLabel={(option) => option.name}
getOptionValue={(option) => option.id}
defaultValue={initialObject}
defaultOptions={options}
onInputChange={loadData} // +
/>
) : null}
</>
)
Run Code Online (Sandbox Code Playgroud)
使用正确的查询获取数据,但选项不会根据我们的服务器数据结果进行更新。我们无法更新 ,defaultOptions因为它仅在初始化期间使用,因此唯一的方法就是返回loadOptions. 但一旦我们这样做了,每次击键都会有 2 次调用。布莱克。经过无数个小时和艰苦实验的奇迹,我们现在发现:
有用的启示:
loadOptions实际上在 inputChange 上触发,所以我们实际上不需要onInputChange.
<AsyncSelect
isClearable
getOptionLabel={(option) => option.name}
getOptionValue={(option) => option.id}
defaultValue={initialObject}
defaultOptions={options}
// onInputChange={loadData} // remove that
loadOptions={loadData} // add back that
/>
Run Code Online (Sandbox Code Playgroud)
事情看起来不错。甚至我们的d搜索也以某种方式自动修复了:
formik或您拥有的任何表单值为此,我们需要一些在选择时触发的东西:
onChange: (no explanation or description)
Run Code Online (Sandbox Code Playgroud)
富有洞察力...不是。我们再次有了一个漂亮而丰富多彩的定义来拯救我们,我们找到了一些线索:
所以我们看到第一个参数(我们不知道它是什么,可以是、、 或 的object数组。然后我们就有了动作的类型。因此,经过一些猜测,我们发现,它必须传递选定的对象:arraynullundefined
我们将setFieldValue函数作为 prop 传递给组件:
onChange={(selectedItem) => {
setFieldValue(fieldName, selectedItem?.id); // fieldName is also passed as a prop
}}
Run Code Online (Sandbox Code Playgroud)
注意:小心,如果你清除选择,它将通过,
null并且selectedItem你的 JS 将因寻找.id未定义而爆炸。要么使用可选链接,要么像我的例子一样将其有条件地设置为''(空字符串,以便 formik 工作)。
这样我们就准备好了一个功能齐全、可重用的自动完成下拉菜单,选择服务器获取异步过滤、可清除的东西。
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import AsyncSelect from 'react-select/async';
export default function AutocompleteComponent({
fieldName,
initialValue,
setFieldValue,
getOptionLabel,
queryField,
}) {
const [options, setOptions] = useState(null);
const [initialObject, setInitialObject] = useState(null);
// this function only finds the item from all the data that has the same id
// that comes from the parent component (my case - formik initial)
const findByValue = (fullData, specificValue) => {
return fullData.find((e) => e.id === specificValue);
};
const loadData = async (query) => {
// load your data using query HERE
return res.data;
};
const getInitial = async () => {
// load your data using query HERE
const fetchedData = res.data;
// match by id your initial value
const initialItem = findByValue(fetchedData, initialValue);
// Set both initialItem and data options so component is initialized
setInitialObject(initialItem);
setOptions(fetchedData);
}
};
// Hit this once in the beginning
useEffect(() => {
getInitial();
}, []);
return (
<>
{options !== null && initialObject !== null ? (
<AsyncSelect
isClearable
getOptionLabel={getOptionLabel}
getOptionValue={(option) => option.id}
defaultValue={initialObject}
defaultOptions={options}
loadOptions={loadData}
onChange={(selectedItem) => {
const val = (selectedItem === null?'':selectedItem?.id);
setFieldValue(fieldName, val)
}}
/>
) : null}
</>
);
}
AutocompleteComponent.propTypes = {
fieldName: PropTypes.string.isRequired,
initialValue: PropTypes.string,
setFieldValue: PropTypes.func.isRequired,
getOptionLabel: PropTypes.func.isRequired,
queryField: PropTypes.string.isRequired,
};
AutocompleteComponent.defaultProps = {
initialValue: '',
};
Run Code Online (Sandbox Code Playgroud)
我希望这可以为您节省一些时间。
| 归档时间: |
|
| 查看次数: |
4167 次 |
| 最近记录: |