The question is published on by Tutorial Guruji team.
I’m trying to prevent a modal element to re-render when it’s supposed to be invisible.
The course I’m following does this by converting the component to a class based component and using shouldComponentUpdate()
but I wanted to check if using React.memo()
did the same thing.
I tried, and it doesn’t, but I’m not sure why.
The component that should not render is this:
import React , {useEffect} from 'react' import Aux from '../../../hoc/Aux'; import Backdrop from '../Backdrop/Backdrop'; import classes from './Modal.module.css'; const Modal = (props) => { useEffect(() => { console.log('[Modal.js] useEffect') }); return ( <Aux> <Backdrop show={props.show} clicked={props.modalClosed} /> <div className={classes.Modal} style={{ transform: props.show ? 'translateY(0)' : 'translateY(-100vh)', opacity: props.show ? '1': '0' }}> {props.children} </div> </Aux>) }; export default React.memo(Modal);
Which is managed by
import React, {Component} from 'react' import Aux from '../../hoc/Aux'; import Burger from '../../components/Burger/Burger' import BuildControls from '../../components/Burger/BuildControls/BuildControls' import Modal from '../../components/UI/Modal/Modal' import OrderSummary from '../../components/Burger/OrderSummary/OrderSummary' const INGREDIENT_PRICES = { salad: 0.5, cheese: 0.4, meat: 1.3, bacon: 0.7 } class BurgerBuilder extends Component { state = { ingredients: { salad: 0, bacon: 0, cheese: 0, meat: 0 }, totalPrice: 4, purchasable: false, purchasing: false } purchaseHandler = () => { this.setState({purchasing: true}); }; purchaseCancelHandler = () => { this.setState({purchasing:false}); }; purchaseContinueHandler = () => { alert('You Continue!') }; updatePurchaseState = (ingredients) => { let purchasable = false; for (let ingredient in ingredients){ if (ingredients[ingredient]>0){ purchasable = true; break; } } this.setState({purchasable:purchasable}) } addIngredientHandler = (type) => { const oldCount = this.state.ingredients[type]; const updatedCount = oldCount +1; const updatedIngredients = { ...this.state.ingredients }; updatedIngredients[type] = updatedCount; const priceAddition = INGREDIENT_PRICES[type]; const oldPrice = this.state.totalPrice; const newPrice = oldPrice + priceAddition; this.setState({totalPrice: newPrice, ingredients: updatedIngredients}); this.updatePurchaseState(updatedIngredients); }; removeIngredientHandler = (type) => { const oldCount = this.state.ingredients[type]; if (oldCount <= 0) return; const updatedCount =oldCount -1; const updatedIngredients = { ...this.state.ingredients }; updatedIngredients[type] = updatedCount; const priceAddition =INGREDIENT_PRICES[type]; const oldPrice = this.state.totalPrice; const newPrice = oldPrice - priceAddition; this.setState({totalPrice: newPrice, ingredients: updatedIngredients}); this.updatePurchaseState(updatedIngredients); }; render () { const disabledInfo = { ...this.state.ingredients }; for (let key in disabledInfo){ disabledInfo[key] = disabledInfo[key] <= 0; } return ( <Aux> <Modal show={this.state.purchasing} modalClosed={this.purchaseCancelHandler}> <OrderSummary ingredients={this.state.ingredients} purchaseCancelled={this.purchaseCancelHandler} purchaseContinued={this.purchaseContinueHandler} price={this.state.totalPrice} /> </Modal> <Burger ingredients={this.state.ingredients}/> <BuildControls ingredientAdded={this.addIngredientHandler} ingredientRemoved={this.removeIngredientHandler} disabled={disabledInfo} price={this.state.totalPrice} purchasable={this.state.purchasable} ordered={this.purchaseHandler}/> </Aux> ); } } export default BurgerBuilder;
With BuildControls
I change the Ingredients
state; but not the props I pass to modal, purchasing
and purchaseHandler
Does changing the ingredients prop I pass to it’s child always prompt a re-render even when Modal
itself is under React.memo()
?
Answer
You are changing one of the props you pass to Modal
– the children
prop. It is passed implicitly by adding children to a react element. And since you are changing the child element it will cause a re-render.