问题描述
我想使用很棒的react-widgets DropDownList从服务器按需加载记录。
我的数据加载全部正常。但是当数据属性更改时,DropDownList组件未显示项目,我收到一条消息
过滤器未返回结果
即使我看到在useEffect挂钩中的组件中填充了数据,也记录了下面的data.length。
我认为这可能是由于“过滤器”道具进行了某种客户端过滤,但是启用此功能是我获得输入控件输入搜索词的方式,并且确实触发了“ onSearch”
此外,如果我使用自己的组件与道具valueComponent或listComponent一起显示,它会炸弹,我相信列表最初是空的。
我在做什么错?我可以使用react-widgets DropDownList以这种方式按需加载数据吗?
//const ItemComponent = ({item}) => <span>{item.id}: {item.name}</span>;
const DropDownUi = ({data,searching,fetchData}) => {
const onSearch = (search) => {
fetchData(search);
}
// I can see the data coming back here!
useEffect(() => {
console.log(data.length);
},[data]);
<DropDownList
data={data}
filter
valueField={id}
textField={name}
onSearch={onSearch}
busy={searching} />
};
解决方法
所以我认为应该加载列表,然后您可以过滤已加载的数据。在示例中,您一开始就没有值,所以列表为空,用胶带粘贴一些文本,然后重新显示列表的值但看起来好像没有被过滤.....
但是我浏览了代码库,直到您没有设置手动打开prop下拉列表组件之前,它似乎还没有准备好。在getDerivedStateFromprops中,只有在打开下一个props时,才读取下一个数据列表。真实
static getDerivedStateFromProps(nextProps,prevState) {
let {
open,value,data,messages,searchTerm,filter,minLength,caseSensitive,} = nextProps
const { focusedItem } = prevState
const accessors = getAccessors(nextProps)
const valueChanged = value !== prevState.lastValue
let initialIdx = valueChanged && accessors.indexOf(data,value)
//-->> --- -- --- -- -- -- -- - - - - - - - - - --- - - --------
//-->>
if (open)
data = Filter.filter(data,{
filter,textField: accessors.text,})
const list = reduceToListState(data,prevState.list,{ nextProps })
const selectedItem = data[initialIdx]
const nextFocusedItem = ~data.indexOf(focusedItem) ? focusedItem : data[0]
return {
data,list,accessors,lastValue: value,messages: getMessages(messages),selectedItem: valueChanged
? list.nextEnabled(selectedItem)
: prevState.selectedItem,focusedItem:
(valueChanged || focusedItem === undefined)
? list.nextEnabled(selectedItem !== undefined ? selectedItem : nextFocusedItem)
: nextFocusedItem,}
}
我会尝试:
<DropDownList
data={data}
filter
open
valueField={id}
textField={name}
onSearch={onSearch}
busy={searching} />
};
如果可行,那么您只需要 自己管理打开状态。
,知道了!这个问题与您传递给组件的filter
属性有关。过滤器不能使用true
作为值,否则将导致突然的行为,如您遇到的行为。
此用法将解决您的问题:
<DropdownList
data={state.data}
filter={() => true} // This was the miss/fix ?
valueField={"id"}
textField={"name"}
busy={state.searching}
searchTerm={state.searchTerm}
onSearch={(searchTerm) => setState({ searchTerm })}
busySpinner={<span className="fas fa-sync fa-spin" />}
delay={2000}
/>
工作演示
我在codesandbox尝试过的整个代码:
警告:输入为空时,您可能必须处理值的清除。 我认为这样做的逻辑与问题陈述无关。如果您愿意,我也可以进行更新。
此外,当fakeAPI
更改时,我添加了一个searchTerm
,可在2秒内解析出模拟数据(假超时以查看加载状态)。
import * as React from "react";
import "./styles.css";
import { DropdownList } from "react-widgets";
import "react-widgets/dist/css/react-widgets.css";
// Coutesy: https://usehooks.com/useDebounce
import useDebounce from "./useDebounce";
interface IData {
id: string;
name: string;
}
const fakeAPI = () =>
new Promise<IData[]>((resolve) => {
window.setTimeout(() => {
resolve([
{
name: "NA",id: "user210757"
},{
name: "Yash",id: "id-1"
}
]);
},2000);
});
export default function App() {
const [state,ss] = React.useState<{
searching: boolean;
data: IData[];
searchTerm: string;
}>({
data: [],searching: false,searchTerm: ""
});
const debounceSearchTerm = useDebounce(state.searchTerm,1200);
const setState = (obj: Record<string,any>) =>
ss((prevState) => ({ ...prevState,...obj }));
const getData = () => {
console.log("getting data...");
setState({ searching: true });
fakeAPI().then((response) => {
console.log("response: ",response);
setState({ searching: false,data: response });
});
};
React.useEffect(() => {
if (debounceSearchTerm) {
getData();
}
},[debounceSearchTerm]);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<DropdownList
data={state.data}
filter={() => true} // This was the miss/fix ?
valueField={"id"}
textField={"name"}
busy={state.searching}
searchTerm={state.searchTerm}
onSearch={(searchTerm) => setState({ searchTerm })}
busySpinner={<span className="fas fa-sync fa-spin" />}
delay={2000}
/>
</div>
);
}
如果您对此还有更多疑问,请告诉我