Liftup Pattern
In contrast to the liftdown pattern,the pattern that lifts up a part of component that depends on the state can prevents unnecessary rendering.
An example below shows <SuperSlowComponent/> when hide is typed in the form.
import { useState } from "react";
function SuperSlowComponent() {
const now = performance.now();
while (performance.now() - now < 200) {}
return <div>Super slow component</div>;
}
function Form({ name, setName }) {
return (
<>
<label htmlFor="name">Name</label>
<input
id="name"
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</>
);
}
export default function App() {
const [name, setName] = useState("");
return (
<div className="app">
<Form name={name} setName={setName} />
{name !== "hide" && <SuperSlowComponent />}
</div>
);
}
This method invokes rerendering the slow component everytime you type values in the field. For now, let's go back to managing useState in the <Form /> component instead of calling it from <App />.
By using liftup pattern, The difference from liftdown pattern is passing the slow component as a children. Since children is simply a prop, it is not affected by changes in state and therefore will not be re-rendered.
import { useState } from "react";
function SuperSlowComponent() {
const now = performance.now();
while (performance.now() - now < 200) {}
return <div>Super slow component</div>;
}
function Form({ children }) {
const [name, setName] = useState("");
return (
<>
<label htmlFor="name">Name</label>
<input
id="name"
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
{name !== "hide" && children}
</>
);
}
export default function App() {
return (
<Form>
<SuperSlowComponent />
</Form>
);
}
As a variation of the lift-up pattern, there is also a pattern where components are passed as Props instead of being passed as children.
import { useState } from "react";
function SuperSlowComponent() {
const now = performance.now();
while (performance.now() - now < 200) {}
return <div>Super slow component</div>;
}
function Form({ left, right }) {
const [name, setName] = useState("");
return (
<>
{left}
<label htmlFor="name">Name</label>
<input
id="name"
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
{right}
</>
);
}
export default function App() {
return (
<div className="app">
<Form right={<SuperSlowComponent />} left={<h1>Hello</h1>} />
</div>
);
}
Top comments (0)