Search code examples
javascriptreactjsreact-hooksreact-usememo

Only show matching string in array when using 'useMemo' in react


I have an autocomplete input field and running into issues when initially hiding the output in my array. Instead of showing all my items when mounted, I just want to show the matching string. Leaving my state empty const [filteredRecipes, setFilteredRecipes] = useState(); will throw in error in my loop.

Codesanbox: https://codesandbox.io/s/quzwg?file=/App.js:251-313

Js:

export default function App() {
  const items = useMemo(
    () => ["item1", "item2", "anotheritem", "yetanotheritem", "myitem"],
    []
  );

  const [search, setSearch] = useState("");
  const [filteredRecipes, setFilteredRecipes] = useState(items);

  const handleSearchChange = event => {
    setSearch(event.target.value);
  };

  useEffect(() => {
    setFilteredRecipes(
      items.filter(el => el.toLowerCase().includes(search.toLowerCase()))
    );
  }, [search, items]);

  return (
    <div>
      <input
        type="search"
        placeholder="type here to filter"
        value={search}
        onChange={handleSearchChange}
      />
      <div>
        {filteredRecipes.map(recipe => (
          <p>{recipe}</p>
        ))}
      </div>
    </div>
  );
}

Solution

  • If I'm understanding your question correctly, in your example filteredRecipes are the autocomplete suggestions that you want to initially hide when mounting, or, making an assumption here, whenever the search value is falsey. You can do this by conditionally filtering on search state being truthy/falsey. All strings will include the empty string (''), so you want to handle this case differently.

    setFilteredRecipes(
      search
        ? items.filter((el) => el.toLowerCase().includes(search.toLowerCase()))
        : []
    );
    

    Code

    export default function App() {
      const items = useMemo(
        () => ["item1", "item2", "anotheritem", "yetanotheritem", "myitem"],
        []
      );
    
      const [search, setSearch] = useState("");
      const [filteredRecipes, setFilteredRecipes] = useState([]);
    
      const handleSearchChange = (event) => {
        setSearch(event.target.value);
      };
    
      useEffect(() => {
        setFilteredRecipes(
          search
            ? items.filter((el) => el.toLowerCase().includes(search.toLowerCase()))
            : []
        );
      }, [search, items]);
    
      return (
        <div>
          <input
            type="search"
            placeholder="type here to filter"
            value={search}
            onChange={handleSearchChange}
          />
          <div>
            {filteredRecipes.map((recipe) => (
              <p>{recipe}</p>
            ))}
          </div>
        </div>
      );
    }
    

    Edit only-show-matching-string-in-array-when-using-usememo-in-react