In my case here, I want to avoid the component <Checkout/> from re-rendering once I replace the url props.history.replace(props.match.path + '/contact-data' to load the component <ContactData/>.
As it can be seen on useEffect when <Checkout/> loads it gets a query tail on the url, something like this: http://localhost:3000/checkout?cheese=0&salad=0&special=0&veggie=1. Then I redirect to the url, having it like this: http://localhost:3000/checkout/contact-data, which renders <ContactData/> below , having both <Checkout/> & <ContactData/> on the screen.
My question is regarding useEffect. If I add a props.location.search as a dependency of useEffect, useEffect will cause a re-render of <Checkout/>, acting somehow like ComponentDidUpdate every time props.location.search changes.
On this use case, when I replace the url in order to load <ContactData/>, props.location.search will change and <Checkout/> would re-render if I had the dependency added, as explained above.
Now, I solved this behaviour by not adding the dependency to useEffect and still leaving the array of deps empty, forcing useEffect to run just once. Is this a bad practice? Would there be a proper way of doing this without cheating on useEffect?
useEffect(() => {
const query = new URLSearchParams(props.location.search)
const ingredients = {};
for (let param of query.entries()) {
ingredients[param[0]] = +param[1]
}
setNewOrder(ingredients)
},[props.location.search])
Even using useEffect with an empty array of dependencies I notice that the <Checkout/> still re-renders, but off course, not running the code inside useEffect on this new render cycle.
Would it be possible to really avoid <Checkout/> from re-rendering here?
import React, {useEffect, useState, Fragment, Suspense} from 'react'
import {withRouter, Route} from "react-router-dom";
import CheckoutSummary from "../../components/CheckoutSummary/CheckoutSummary";
const ContactData = React.lazy(() => import("./ContactData/ContactData"))
function Checkout(props) {
const [newOrder, setNewOrder] = useState(null);
const returnToOrderCreationHandler = () => {
props.history.goBack()
}
const confirmOrderHandler = () => {
props.history.replace(props.match.path + '/contact-data')
}
useEffect(() => {
const query = new URLSearchParams(props.location.search)
const ingredients = {};
for (let param of query.entries()) {
ingredients[param[0]] = +param[1]
}
setNewOrder(ingredients)
},[])
return (
<Fragment>
<CheckoutSummary ingredients={newOrder}
cancelCheckout={returnToOrderCreationHandler}
confirmCheckout={confirmOrderHandler}/>
<Route path={props.match.path + '/contact-data'} render={() =>
<Suspense fallback={<h1>Loading...</h1>}><ContactData/></Suspense>}/>
</Fragment>
)
}
export default withRouter(Checkout)