Search code examples
javascriptreactjsdrop-down-menureact-widgets

react-widgets DropDownList dynamic load on demand


I would like to use the awesome react-widgets DropDownList to load records on demand from the server.

My data load all seems to be working. But when the data prop changes, the DropDownList component is not displaying items, I get a message

The filter returned no results

enter image description here

Even though I see the data is populated in my component in the useEffect hook logging the data.length below.

enter image description here

I think this may be due to the "filter" prop doing some kind of client side filtering, but enabling this is how I get an input control to enter the search term and it does fire "onSearch"

Also, if I use my own component for display with props valueComponent or listComponent it bombs I believe when the list is initially empty.

What am I doing wrong? Can I use react-widgets DropDownList to load data on demand in this manner?

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

Solution

  • Got it! This issue is with the filter prop that you are passing to the component. The filter cannot take a true as value otherwise that would lead to abrupt behavior like the one you are experiencing.

    enter image description here

    This usage shall fix your problem:

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

    Working demo

    enter image description here

    The entire code that I had tried at codesandbox:

    Warning: You might have to handle the clearing of the values when the input is empty. I thought that the logic for this was irrelevant to the problem statement. If you want, I can update that as well.

    Also, I added a fakeAPI when searchTerm changes that resolves a mocked data in 2 seconds(fake timeout to see loading state).

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

    Let me know if you have more queries on this 😇