We have the initial useEffect()
being called to get all the data from the API.
const [items, setItems] = React.useState([]);
const [filteredItems, setFilteredItems] = React.useState([]);
useEffect(() => {
axios.get(process.env.REACT_APP_API_URI "item/getAll", { headers: auth }).then((res) => {
setItems(res.data);
setFilteredItems(res.data);
})
axios.get(process.env.REACT_APP_API_URI "role/getAll", { headers: auth }).then((res) => {
setRoles(res.data);
})
}, [])
Than an OnChange
occurs which triggers the handleFilters()
method. This method checks if the item
has the same role
as specified. If it does, put it in a temporary array. Lastly set the filteredItems
to the new filteredItems
.
function handleFilters() {
let tempArray = [];
items.forEach((item) => {
if (item.role.name.toString().toLowerCase().includes(role.toLowerCase()) && !tempArray.includes(item)) {
tempArray.push(item);
}
})
setFilteredItems(tempArray);
}
These filteredItems
are rendered in the return. Like this
return (
//handleFilters() is triggered here
{filteredItems.map((item, index) => (
<Box key={index} sx={{ ":hover": { backgroundColor: "#F5F5F5" } }}>
//etc do stuff with the item properties
</Box>
))}
)
Now the problem is, that when I set some filters and trigger the handleFilters()
method. The filteredItems
doesn't change instantly, instead they get changed the NEXT time handleFilters()
is triggered. Which means that the render is always one step too late.
I also tried to put filteredItems
in the useEffect empty array, but that doesn't work. I think it's because the axios call is also getting executed which resets the filteredItems
back to all items.
CodePudding user response:
This is what I would do if I need a filter. I am assuming you have a dropdown select to change the selected role (role
) variable.
const [items, setItems] = React.useState([]);
const [role, setRole] = React.useState(null);
const [roles, setRoles] = React.useState([]);
const filteredItems = items
.filter(item => {
return item.role.name.toString().toLowerCase().includes(role?.toLowerCase())
})
.filter((item, index, array) => {
return !array.includes(item)
})
In the first filter function, you can see the variable role
is used, that is your selected role. When you selected role is changed, it will re-render the page as role
is with useState
. When it re-render, the filteredItems
will also be re-construct while the items
still remain from the useEffect
hook
CodePudding user response:
I think this has already happened to me and the solution for me was to wrap the function in a useCallback()
hook with items
and setFilteredItems
in the dependency array:
const handleFilterItems = useCallback(() => {
// your filtering logic
},[items, setFilteredItems])
Does this help?