"Alternative Approach Before Using Memo in React"

"Alternative Approach Before Using Memo in React"

In this post, I aim to introduce two distinct techniques that, despite their simplicity, tend to go unnoticed in terms of their positive impact on rendering performance.

It's worth noting that these techniques complement your existing knowledge and are not meant to substitute for memo or useMemo. However, they are often a valuable starting point to consider.

import { useState } from 'react';

export default function MyComponent() {
  let [backgroundColor, setBackgroundColor] = useState('blue');
  return (
    <div>
      <input
        value={backgroundColor}
        onChange={(e) => setBackgroundColor(e.target.value)}
      />
      <p style={{ backgroundColor }}>Greetings, world!</p>
      <SlowComponent />
    </div>
  );
}

function SlowComponent() {
  let now = performance.now();
  while (performance.now() - now < 100) {
    // Simulated delay -- do nothing for 100ms
  }
  return <p>I am a very time-consuming component.</p>;
}
        

The problem is that whenever backgroundColor changes inside MyComponent, we will re-render <SlowComponent /> which we’ve artificially delayed to be very slow.

I could easily apply memo() to it and consider the problem solved, but since there are numerous articles already covering that approach, I'd prefer to explore two distinct solutions instead.

Solution 1: Move State Down

  • Upon closer examination of the rendering code, you'll observe that only a portion of the returned tree is concerned with the current color.
  • So let’s extract that part into a MyForm component and move state down with it
  • Now if the backgroundColor changes, only the MyForm re-renders. Problem solved.

export default function MyComponent() {
  return (
    <>
      <MyForm />
      <SlowComponent />
    </>
  );
}

function MyForm() {
  let [backgroundColor, setBackgroundColor] = useState('blue');
  return (
    <>
      <input
        value={backgroundColor}
        onChange={(e) => setBackgroundColor(e.target.value)}
      />
      <p style={{ backgroundColor }}>Greetings, world!</p>
    </>
  );
}        
Solution 2: Lift Content Up

The previously mentioned solution is not effective when the state is utilized higher up in the component tree. To illustrate, if we place the backgroundColor state on the parent <div>, it poses a challenge.

export default function MyComponent() {
  let [backgroundColor, setBackgroundColor] = useState('blue');
  return (
    <div style={{ backgroundColor }}>
      <input
        value={backgroundColor}
        onChange={(e) => setBackgroundColor(e.target.value)}
      />
      <p style={{ backgroundColor }}>Greetings, world!</p>
      <SlowComponent />
    </div>
  );
}        

Below solutions We've divided the MyComponent into two parts. The components and the state variable, which rely on the backgroundColor, have been relocated to the BackgroundHOC component.

The components that are not influenced by the backgroundColor have remained within the MyComponent and are provided to the BackgroundHOC as JSX content, commonly referred to as the children prop.

Whenever the backgroundColor undergoes changes, the BackgroundHOC component re-renders. However, it retains the same children prop it received from the MyComponent during the previous render. Consequently, React does not traverse through that particular subtree.

Consequently, the <SlowComponent /> component remains unaffected and doesn't undergo re-rendering.


export default function MyComponent() {
  return (
    <BackgroundHOC>
      <p>Greetings, world!</p>
      <SlowComponent />
    </BackgroundHOC>
  );
}

function BackgroundHOC({ children }) {
  let [backgroundColor, setBackgroundColor] = useState("blue");
  return (
    <div style={{ backgroundColor }}>
      <input
        value={backgroundColor}
        onChange={(e) => setBackgroundColor(e.target.value)}
      />
      {children}
    </div>
  );
}
        

Prior to implementing optimizations such as memo or useMemo, it's worth considering whether you can segregate the components that undergo changes from those that remain static.

What's intriguing about these techniques is that their primary focus isn't solely on enhancing performance. Utilizing the children prop to divide components typically simplifies the data flow within your application and minimizes the necessity to pass numerous props down the component tree. Improved performance, in scenarios like this, serves as an additional advantage rather than the primary objective.

Interestingly, this pattern also unlocks further performance advantages in the future.

As an Example, once Server Components are stable and suitable for integration, our BackgroundHOC component might receive its children directly from the server. This means that either the entire <SlowComponent /> component or its individual components could be processed on the server side, and even when a top-level React state update occurs, it would seamlessly bypass those parts on the client side.

That’s something even memo couldn’t do! But again, both approaches are complementary. Don’t neglect moving state down (and lifting content up!)

Maghdum Hussain

Hyperautomation | Intelligent Automation | AI, ML | MS in Data Science

1 年

Absolutely agree with this article! ?? React's composition model offers such elegant solutions for managing state and component isolation. The idea of utilizing the children prop to separate dynamic and static parts not only improves performance but also enhances code maintainability. And the prospect of integrating Server Components in the future adds another layer of excitement to the mix. Great insights! ?? #React #Optimization #WebDevelopment #CodeSimplicity

Noor Ayesha

Senior Data Engineer|Data Scientist|Gaming|Chess| A.I | Reinforcement Learning|Deep Q Learning|Data Strategy| Data Manager

1 年

Great insights on optimizing React components and improving performance! The idea of using the `children` prop for component separation is a fantastic approach that can simplify data flow. Looking forward to the future potential with Server Components. #React #PerformanceOptimization #ReactDevelopment

要查看或添加评论,请登录

社区洞察

其他会员也浏览了