skip to Main Content

I want to create a filtering function that trigger when receiving a input value event in react useState but i do not see is doing anything when I start typing in. This is my Search component

export function Search({categories, onSearch}){
    const [searchText, setSearchText] = useState('');

    const filterCategories = () => {
        const filteredCategories = categories.filter(category =>
          category.name.toLowerCase().includes(searchText.toLowerCase())
        );
        onSearch(filteredCategories);
      };
    
      const handleInputChange = event => {
        setSearchText(event.target.value);
        filterCategories();
      };


    return (
        <div className="flex items-center"> 
        <form className='flex space-x-1' >
         <input 
                     type="text"
                     className="block w-full px-4 py-2 text-purple-700 bg-white border rounded-full focus:border-purple-400 focus:ring-purple-300 focus:outline-none focus:ring focus:ring-opacity-40"
                     placeholder="Search..."  
                     value={searchText}
                     onChange={handleInputChange}
                    />
       
        </form>
        </div>
    )
}

Then is being used here

const Layout = ({ categories, children }) => {
  const [filteredCategories, setFilteredCategories] = useState(categories);

  const handleSearch = (filteredCategories) => {
    setFilteredCategories(filteredCategories);
  };

  return (
    <div>
      {/* ... */}
      <Search categories={categories} onSearch={handleSearch} />
      {/* ... */}
      {children}
    </div>
  );
};

export default Layout;

and That goes into the Home component

export default function Home({ posts, categories }) {

  return (
    <Layout categories={categories}>
      <div className="mt-20">
        <main className="flex flex-col justify-center items-center h-screen pt-10 pb-30">
          {/* Render posts */}
        </main>
      </div>
    </Layout>
  );
}

Is there anything I should do to make this work?

3

Answers


  1. In the Layout component you are passing categories value to your Search component, you probably meant to pass filteredCategories

    const Layout = ({ categories, children }) => {
      const [filteredCategories, setFilteredCategories] = useState(categories);
    
      const handleSearch = (filteredCategories) => {
        setFilteredCategories(filteredCategories);
      };
    
      return (
        <div>
          {/* ... */}
          <Search
            categories={filteredCategories} // here
            onSearch={handleSearch}
          />
          {/* ... */}
          {children}
        </div>
      );
    };
    
    export default Layout;
    

    (filteredCategories was unused which made you feel that nothings was happening)

    Login or Signup to reply.
  2. Your code seems correct. Ensure categories have valid data with name property. To debug, add console.log in handleInputChange and filterCategories to see if they’re triggered and check the console for issues. If the input change and filtering events are working, it might be a styling or UI issue. Look at my code bellow i updated

    import React, { useState } from 'react';
    
    export function Search({ categories, onSearch }) {
      const [searchText, setSearchText] = useState('');
    
      const filterCategories = () => {
        const filteredCategories = categories.filter(category =>
          category.name.toLowerCase().includes(searchText.toLowerCase())
        );
        onSearch(filteredCategories);
      };
    
      const handleInputChange = event => {
        const searchText = event.target.value;
        console.log("Input Change:", searchText);
        setSearchText(searchText);
        filterCategories();
      };
    
      return (
        <div className="flex items-center">
          <form className="flex space-x-1">
            <input
              type="text"
              className="block w-full px-4 py-2 text-purple-700 bg-white border rounded-full focus:border-purple-400 focus:ring-purple-300 focus:outline-none focus:ring focus:ring-opacity-40"
              placeholder="Search..."
              value={searchText}
              onChange={handleInputChange}
            />
          </form>
        </div>
      );
    }
    Login or Signup to reply.
  3. your handleSearch function passed as props onSearch to Search component expects an arg filteredCategories to set it to its state filteredCategories.

    Now you are calling it each time you type in the input:

    onChange={handleInputChange}
    

    what it does ?

    const filteredCategories = categories.filter(category => 
    category.name.toLowerCase().includes(searchText.toLowerCase()));
    onSearch(filteredCategories);
    

    so you filtter based on searchText then you call onSearch passing the result of your filter i.e filteredCategories, however, this is not the correct approach since searchText won’t be updated immediately but when the component rerenders (so you are a step late), therefore, you have to filter based on the input value not the state, in fact, with your implementation, you don’t even need the searchText state at all:

    const handleInputChange = event => {
       filterCategories(event.target.value);
    };
    
    // ...
    
    const filterCategories = (value) => {
    const filteredCategories = categories.filter(category => 
    category.name.toLowerCase().includes(value.toLowerCase()));
    onSearch(filterCategories)
    }
    

    Now you have the correct logic to update filteredCategories state in the parent component (Layout) and you should see the expected filtred data logged each time you type in the child component input causing the layout component to rerender:

    const Layout = ({ categories, children }) => {
      const [filteredCategories, setFilteredCategories] = useState(categories);
      console.log("function called: ", filteredCategories);
      // ...
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search