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 是开集时才读取下一个数据列表。为真

来自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,
        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>
  );
}

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