react-widgets DropDownList 按需动态加载
react-widgets DropDownList dynamic load on demand
我想使用很棒的 react-widgets DropDownList 从服务器按需加载记录。
我的数据加载似乎一切正常。但是当数据属性改变时,DropDownList 组件不显示项目,我收到一条消息
The filter returned no results
尽管我看到数据已填充到我的组件中,但在下面记录 data.length 的 useEffect 挂钩中。
我认为这可能是由于“过滤器”道具进行了某种客户端过滤,但启用此功能是我获得输入控件以输入搜索词的方式,它确实触发了“onSearch “
此外,如果我使用自己的组件来显示道具 valueComponent or 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} />
};
所以我认为应该加载列表然后你可以过滤你加载的data.In你的例子在开始你没有价值所以列表是空的,你录入一些文本然后值重新渲染列表,但看起来没有过滤.....
但是我查看了代码库,直到您不设置手动打开道具下拉列表组件,它才准备就绪。在 getDerivedStateFromprops 中,仅当 in next 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,
searchTerm,
minLength,
caseSensitive,
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:
尝试过的完整代码
警告:当输入为空时,您可能必须处理值的清除。
我认为这样做的逻辑与问题陈述无关。如果你愿意,我也可以更新。
此外,我在 searchTerm
更改时添加了一个 fakeAPI
,可在 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>
);
}
如果您对此有更多疑问,请告诉我
我想使用很棒的 react-widgets DropDownList 从服务器按需加载记录。
我的数据加载似乎一切正常。但是当数据属性改变时,DropDownList 组件不显示项目,我收到一条消息
The filter returned no results
尽管我看到数据已填充到我的组件中,但在下面记录 data.length 的 useEffect 挂钩中。
我认为这可能是由于“过滤器”道具进行了某种客户端过滤,但启用此功能是我获得输入控件以输入搜索词的方式,它确实触发了“onSearch “
此外,如果我使用自己的组件来显示道具 valueComponent or 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} />
};
所以我认为应该加载列表然后你可以过滤你加载的data.In你的例子在开始你没有价值所以列表是空的,你录入一些文本然后值重新渲染列表,但看起来没有过滤.....
但是我查看了代码库,直到您不设置手动打开道具下拉列表组件,它才准备就绪。在 getDerivedStateFromprops 中,仅当 in next 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,
searchTerm,
minLength,
caseSensitive,
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:
尝试过的完整代码警告:当输入为空时,您可能必须处理值的清除。 我认为这样做的逻辑与问题陈述无关。如果你愿意,我也可以更新。
此外,我在 searchTerm
更改时添加了一个 fakeAPI
,可在 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>
);
}
如果您对此有更多疑问,请告诉我