Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

React: Hook not triggering when parent component changes boolean value passed to child

so I have a parent that is responsible for rendering a list of items. When the item is clicked it will send an event to the parent, that will record on a Map the selection state. If selected it passes the selected state to the child so that it can change style. Here’s the code for the parent:

export default function CreateYourMixProductsList(props: ProductsInterface) {
    const selectedProducts: Map<number, Product> = new Map<number, Product>();

function onProductClick(product: Product): void {
    selectedProducts.set(product.id, product);
}

return (
    <>
        <List sx={{width: '100%', bgcolor: 'background.paper'}}>
            {props?.products?.map(product => (
                <ProductListItem key={product.id} product={product}
                                 selected={selectedProducts.has(product.id)}
                                 onClick={(product) => onProductClick(product)} />
            ))}
        </List>
    </>
);

and the child

export default function ProductListItem(props: ProductProps) {
    const [selected, setSelected] = React.useState(false);

    function onClick(product: Product) {
       props.onClick(product);
    }

    useEffect(() => {
        setSelected(!selected);
    }, [props.selected]);

    return (
        <>
            <ListItemButton alignItems="flex-start" onClick={event => {onClick(props.product)}} selected={props.selected ? selected : false}>
//omitted code to keep it short

The useEffect is triggered only on rendering, whilst to my understanding, it should be triggered every time the props passed down is an immutable variable. What am I missing here?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

Lets unwrap this:

Why is the useEffect not running?

Hooks re-run every time a variable in their dependency array changes. Your hook is not running again because the value of props.selected does not change.
You can easily verify this by simply logging the value in the component.

Why is props.selected not changing?

Your click handler correctly sets the value on your Map. However, React does not recognize that a a new value was set inside the map. The component never re-renders and selectedProducts.has() is not called again. So the value of props.selected is indeed still the same.

How can you make React recognize your change?

First of all, you should avoid declaring state like this in your component. Each time this component renders it will re-declare all variables defined inside it (selectedProducts will always be set to a new empty map). Use reacts hook api instead.

To make the variable stick – and reactive – you can simply use it with useState() as you did in your child-component. E.g.:

...
const [selectedProducts, setSelectedProducts] = useState<Map<number, Product>>(new Map<number, Product>());

function onProductClick(product: Product): void {
    selectedProducts.set(product.id, product);
    // Note how we are re-setting the variable to make React aware of the change!
    setSelectedProducts(new Map(selectedProducts));
}
...

It is important to note that Reacts useState hook compares values with tripple-equal (===) to determine whether it should trigger a re-render. Due to the nature of JavaScript (where variables only hold references to objects), setting a new value on a Map will not change its reference. To trigger a re-render you have to replace the Map.

Creating new objects is computationally cheap so this shouldn’t cause any issues most of the times.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading