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)