Skip to content
Today's Tech Byte: Elements, children as props, and re-renders

Today's Tech Byte: Elements, children as props, and re-renders

Posted on:October 24, 2023

If you read my last post, we talked about the “Moving state down pattern” and how it can be used to avoid unnecessary re-renders. But what happens when we can not use this pattern?

“Children as props” pattern

Let’s take a look at the following example, where we have a scrollable area and a component that needs to be moved based on the scroll position.

const MainScrollableArea = () => {
  const [position, setPosition] = useState(300);
  const onScroll = e => {
    // calculate position based on the scrolled value
    const calculated = getPosition(e.target.scrollTop);
    setPosition(calculated);
  };
  return (
    <div className="scrollable-block" onScroll={onScroll}>
      {/* pass position value to the new movable component */}
      <MovingBlock position={position} />
      <VerySlowComponent />
    </div>
  );
};

You can’t move the state down because the state is attached to the div that wraps the app. So, how can we avoid unnecessary re-renders?

const ScrollableWithMovingBlock = ({ content }) => {
  const [position, setPosition] = useState(300);
  const onScroll = e => {
    const calculated = getPosition(e.target.scrollTop);
    setPosition(calculated);
  };
  return (
    <div className="scrollable-block" onScroll={onScroll}>
      <MovingBlock position={position} />
      {content}
    </div>
  );
};

// just pass that slow bunch of stuff to that component as props.

const App = () => {
  const slowComponents = (
    <>
      <VerySlowComponent />
    </>
  );
  return <ScrollableWithMovingBlock content={slowComponents} />;
};

A simpler way to do this is to use the children prop.

const ScrollableWithMovingBlock = ({ children }) => {
  const [position, setPosition] = useState(300);
  const onScroll = e => {
    const calculated = getPosition(e.target.scrollTop);
    setPosition(calculated);
  };
  return (
    <div className="scrollable-block" onScroll={onScroll}>
      <MovingBlock position={position} />
      {children}
    </div>
  );
};

// just pass that slow bunch of stuff to that component as props.

const App = () => {
  return (
    <ScrollableWithMovingBlock>
      <VerySlowComponent />
    </ScrollableWithMovingBlock>
  );
};

If you are like me, this pattern is one of the thing that you use but never really thought about it, and why components as props are not re-rendered when the state is updated.

Why children as props are not re-rendered when the state is updated?

First let’s explain what is an Element in React.

Components is a function that returns Elements, which React then converts into DOM elements and sends to the browser to be drawn on the screen.

const Parent = props => {
  return <Child />;
};

This function returns , which is an Element of a Child Component. Every time we use those brackets on a component, we create an Element. The Element of the Parent component would be .

Element is simply an object that defines a component that needs to be rendered on the screen.

In brief, during re-rendering React compares these current object (Element) with the previous one, and if they are the same, it doesn’t re-render the component.

If we wanted to represent passing a child component as a prop, it would look like this:

{
  type: Parent,
  props: {
    children: {
      type: Child,
      props: {}
    }
  }
}

When the state update in the Parent component is re-rendered, React will examine the values returned by the Parent function both ‘before’ and ‘after’ the state change. In this specific scenario, the ‘before’ value will be a reference to the child component, which is an object created outside the scope of the Parent function and remains unchanged during subsequent calls. Consequently, the comparison of the child component ‘before’ and ‘after’ values will yield ‘true,’ leading React to bypass the re-rendering of this component.

Conclusion

This post was longer than usual because it was difficult to explain the pattern in few words without missing a lot of valuable insights.I hope you learned something new. I know I did.

If you have any suggestions or questions, feel free to reach out to me on Twitter or LinkedIn.

P.S. this post is inspired by the book, but it’s not a summary of it. I’m just sharing what I learned from it. If you want to learn more about React, I highly recommend you to read it.