Search code examples
javascriptreactjsarraysreact-hooksreact-state

I have tried to implement search functionality in react, when I clear the input, I am not getting back the full list


The search functionality works but when I clear the input value, the complete list does not show up. I am using filter method for it, I am not understanding how can I get the full list back.

//search the subscriber in the list
function SearchBar() {
    const { subscriber, setsubscriber } = useContext(Context)

    const handleSearch = (e) => {
        e.preventDefault()
        const text = e.target.value;

        const filteredUser = subscriber.filter((user) => {
            if (user.name.includes(text)) {
                return user.name
            }
        })
        setsubscriber(filteredUser)
    }
    return (
        <div className='searchBar'><TextField
            id="input1"
            label="Search User Name"
            onChange={(e) => handleSearch(e)}
        />
        </div>
    )
}
//list of subscriber
export default function ShowSubscriber() {
    const { subscriber } = useContext(Context)
    const subscribers = subscriber && subscriber.map &&
        subscriber.map((item, i) =>
        (
            <div style={{ display: "flex", marginTop: "20px" }} key={i}>
                <span style={{ fontSize: "25px", marginLeft: "20px", marginRight: "20px" }}>{item.name} {item.subscribedToChannel}</span>
                <EditSubscriber />
                <DeleteSubscriber /></div>))

    return subscribers;
}

Solution

  • Don't mutate your source of truth, e.g. the subscriber value/state being provided by the Context. Filtering is a reducing action, and once elements are removed from the source array they can't be brought back without either re-fetching all the data, or caching a separate copy of it or keeping track of what was removed. This would be extraneous unnecessary work and logic.

    I suggest storing the filtering value in to the Context and provide either an already filtered subscriber value, or provide both subscriber and the filter value to consumers for them to apply and compute the derived "state" value.

    Examples:

    • Compute and provide derived filtered subscribers array

      Context.jsx

      const [search, setSearch] = React.useState("");
      
      ...
      
      const filteredSubscribers = React.useMemo(() => {
        return (subscriber ?? []).filter(
          item => item.name.toLowerCase().includes(search)
        );
      }, [search, subscriber]);
      
      ...
      
      function SearchBar() {
        const { search, setSearch } = useContext(Context);
      
        const handleSearch = (e) => {
          e.preventDefault()
          setSearch(e.target.value.toLowerCase());
        }
      
        return (
          <div className='searchBar'>
            <TextField
              id="input1"
              label="Search User Name"
              value={search}
              onChange={handleSearch}
            />
          </div>
        )
      }
      
      export default function ShowSubscriber() {
        const { filteredSubscribers } = useContext(Context);
      
        return filteredSubscribers
          .map((item, i) => (
            <div style={{ display: "flex", marginTop: "20px" }} key={i}>
              <span
                style={{
                  fontSize: "25px",
                  marginLeft: "20px",
                  marginRight: "20px"
                }}
              >
                {item.name} {item.subscribedToChannel}
              </span>
              <EditSubscriber />
              <DeleteSubscriber />
            </div>
          ));
      }
      
    • Provide both subscriber and search to consumers

      Context.jsx

      const [search, setSearch] = React.useState("");
      
      ...
      
      function SearchBar() {
        const { search, setSearch } = useContext(Context);
      
        const handleSearch = (e) => {
          e.preventDefault()
          setSearch(e.target.value.toLowerCase());
        }
      
        return (
          <div className='searchBar'>
            <TextField
              id="input1"
              label="Search User Name"
              value={search}
              onChange={handleSearch}
            />
          </div>
        )
      }
      
      export default function ShowSubscriber() {
        const { search, subscriber } = useContext(Context);
      
        return subscriber
          ?.filter(item => item.name.toLowerCase().includes(search))
          .map((item, i) => (
            <div style={{ display: "flex", marginTop: "20px" }} key={i}>
              <span
                style={{
                  fontSize: "25px",
                  marginLeft: "20px",
                  marginRight: "20px"
                }}
              >
                {item.name} {item.subscribedToChannel}
              </span>
              <EditSubscriber />
              <DeleteSubscriber />
            </div>
          ));
      }