Home > Back-end >  How to re-render state when React useState changes?
How to re-render state when React useState changes?

Time:12-06

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?

  • Related