0
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
Reset to default
0
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)
0
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>
);
}
0
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);
// ...
}
Not the answer you're looking for? Browse other questions tagged
or ask your own question.
or ask your own question.
|