react-widgets DropDownList按需动态加载

问题描述

我想使用很棒的react-widgets DropDownList从服务器按需加载记录。

我的数据加载全部正常。但是当数据属性更改时,DropDownList组件未显示项目,我收到一条消息

过滤器未返回结果

enter image description here

即使我看到在useEffect挂钩中的组件中填充了数据,也记录了下面的data.length。

enter image description here

我认为这可能是由于“过滤器”道具进行了某种客户端过滤,但是启用此功能是我获得输入控件输入搜索词的方式,并且确实触发了“ onSearch

此外,如果我使用自己的组件与道具valueComponentlistComponent一起显示,它会炸弹,我相信列表最初是空的。

我在做什么错?我可以使用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时,才读取下一个数据列表。真实

来自DropDwonList

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作为值,否则将导致突然的行为,如您遇到的行为。

enter image description here

此用法将解决您的问题:

      <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}
      />

工作演示

enter image description here

我在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>
  );
}

如果您对此还有更多疑问,请告诉我