Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent rerendering casued by replacement between simple react components

Tags:

reactjs

function A() {
  return <HeavyComponent someProp={true} />;
}

function B() {
  return <HeavyComponent someProp={false} />;
}

function C() {
  const [state, setState] = useState(true);
  return state ? <A /> : <B />;
}

function D() {
  const [state, setState] = useState(true);
  return state ? A() : B();
}

As you can see, A and B do very simple jobs. When state in C changes from true to false, react will remove the element which A has rendered and mount the new one B render. This causes HeavyComponent render from scratch.

If I use D instead of C, the result will be exactly the same. However. The rendering will be more efficient since D will update HeavyComponent rather than remove-and-render-new-one.

The problem is that I want to export both A and B in a library and it's hard to expect other programmers to use A and B in an efficient way like in D.

I think you can point out that I don't need to define A and B. But it's just a simplified example. In real practice, I have more than one props and also more components. Each component represents the semantic of the combination of props passing to HeavyComponent by name of itself. I'll also export HeavyComponent directly, but the user will get confused about its props at the first time. So it would be better export handy components A and B.

Is there any way to make A and B work as in D, even if the programmer use them as in C?

like image 470
12412316 Avatar asked Feb 22 '26 03:02

12412316


2 Answers

You probably meant remounting, not rerendering. The answer is you can't, not while using C.

And with D, A and B can no longer handle state and effects; making them more of a utility function and less component.

What you could do is export a custom hook to return the default props to be spread into <HeavyComponent>

function E() {
    const [state, setState] = useState(false)
    const aProps = useA()
    const bProps = useB()
    const props = state ? aProps : bProps

    return <HeavyComponent {...props} />
}

Of course you don't have to use hooks (you can just use a regular function) but this enables you to include state and effects, as if it were a full fledged <A> component itself, with the benefit of no unmounting and remounting.

like image 163
Mordechai Avatar answered Feb 24 '26 15:02

Mordechai


As another possible workaround you can create a component that encapsulates different props combinations, for example:

function DecoratedHeavyComponent({ variant, props }) {

  const variantProps = {
    A: { someProp: true },
    B: { someProp: false },
    // etc...
  }

  return <HeavyComponent {...props} {...variantProps[variant]} />;
}

Can be further used like this:

function C() {
  const [state, setState] = useState(true);
  return <DecoratedHeavyComponent variant={ state ? 'A' : 'B' } />;
}
like image 31
oozywaters Avatar answered Feb 24 '26 16:02

oozywaters