DEV Community

Cover image for The perfect React's component doesn't exist. 🀯
Bassem
Bassem

Posted on • Originally published at bassemmohamed.me

The perfect React's component doesn't exist. 🀯

Hey devs from all over the world 😊

In today's post, I want to tell you all about React's performance. How can we optimize our react components to reduce the number of undesired re-renders? I will be talking about React's PureComponent class, Memos and the truly awesome shouldComponentUpdate method.

Oki, As most of you know. React uses the virtual DOM πŸ”₯to reduce the costly real DOM manipulation operations. This virtual DOM is a representation of the actual DOM but built with javascript. When a component updates, React builds the new virtual DOM then compares it with the previously rendered one to decides whether an actual DOM update is required or not. πŸ‘¨β€βš–οΈ

That what makes React stand out from other frontend frameworks out there. πŸ₯‡Now, Let's talk about how to make your React components stand out. πŸ’ͺ

The perfect React's component doesn't exist. 🀯

Ohh yeah! I love minimalism and I like to think that we are applying it's concepts here. Think about it for a second. LESS CODE == LESS TROUBLE, isn't it? 🀯

We can discuss this in another article though. In our today's article, it is more like LESS RE-RENDERS == MORE PERFORMANCE, We want to stabilize our component's as much as we can. cause every re-render means that react will at least check for the difference between new and old virtual DOM. If we don't need that re-render in the first place. That just means computations down the drain. which is obviously a big no-no when it comes to performance. πŸ™…β€β™‚οΈ

shouldComponentUpdate to the rescue πŸš€

I am sure most of you guys know about shouldComponentUpdate but if you don't, let me give a quick introduction. It is a component lifecycle method that tells React whether to continue updating the component or not. It runs every time there is a change in the props or the state and it defaults to true.

So for example, if we have a component with a shouldComponentUpdate like this :

    shouldComponentUpdate(nextProps, nextState) {
        return false;
    }
Enter fullscreen mode Exit fullscreen mode

It will basically never ever update without forcing it. shouldComponentUpdate doesn't get called for the initial render or when forceUpdate() is used.

Wait a sec! Are you saying we should write a shouldComponentUpdate method by hand for every component just to prevent a couple of undesired renders ?! 🀯Nobody got time for this! 😠

Not exactly! πŸ™„

What is React's PureComponent? πŸ€”

It is similar to React's component class but it implements shouldComponentUpdate with a shallow prop and state comparison by default.

In other words, every prop/state update in a PureComponent will not trigger re-render unless there is a shallow difference between current & previous props or current & previous state.

This shallow part is a little tricky, as it could lead to false-negatives ( Not updating when we actually want a re-render ) in the case of complex data structures like arrays or objects. let's go for an example.

    state = {
        itemsArray: []
    } 

    onSomeUserAction = (item) => {
        const itemsArray = this.state.itemsArray;
        itemsArray.push(item);
        this.setState({ itemsArray })
    }
Enter fullscreen mode Exit fullscreen mode

Now imagine this scenario where we have an array in the state and we want to push an item into that array on some user action.

This will actually produce a false negative if it is a PureComponent. After this setState, shouldComponentUpdate will shallowly compare the old state to the new one just like this this.state == nextState and because our itemsArray reference is exactly the same this condition will be truthful and the PureComponent will not re-render. This is also a similar case for objects like this example.

    state = {
        user: {}
    } 

    onSomeUserAction = (name) => {
        const user = this.state.user;
        user.name = name;
        this.setState({ user })
    }
Enter fullscreen mode Exit fullscreen mode

Immutable everywhere πŸ™Œ

We can fix this issue by using forceUpdate() but thats not exactly elegant and it goes against everything we just said so scrap that!

What we should do is create a new object/array every time like this :

    state = {
        itemsArray: []
    } 

    onSomeUserAction = (item) => {
        const itemsArray = this.state.itemsArray;
        this.setState({ itemsArray: [...itemsArray, item] })
    }

or in case of objects

    state = {
        user: {}
    } 

    onSomeUserAction = (name) => {
        const user = this.state.user;
        this.setState({ user: {...user, name} })
    }
Enter fullscreen mode Exit fullscreen mode

Using some not so new JavaScript features like destructing and the spread operator. It doesn't only look cooler but it is also considered a whole new object. Now the this.state == nextState is no longer truthful and the shouldComponentUpdate is no longer producing a false-negative.

Now, what about functional components? Well, you should use Memo for that like this

    const MyComponent = React.memo(function MyComponent(props) {
      /* render using props */
    });
Enter fullscreen mode Exit fullscreen mode

Memo is just like PureComponent but for functional components instead of classes.

With PureComponent or Memo and creating new object/arrays with setState, We can now safely celebrate our better performing components, give yourselves a great round of applause. πŸ‘πŸ‘

You made it all the way here! Thanks for reading and I really hope you enjoyed it. If you did, Don't forget to let me know and if you really liked it follow me on twitter to never miss a future post. 😊

As always,
Happy coding πŸ”₯πŸ”₯
β€œΩƒΩˆΨ―Β Ψ¨Ψ³ΨΉΨ§Ψ―Ψ©β€

Top comments (2)

Collapse
 
jsco profile image
Jesco Wuester • Edited

I feel like this article is falling into a common performance trap. React is really fast by default and these deep equality checks and so on are usually slower than just rerendering the component. For performance, measure first and if your component is slow (which very very rarely happens) you can think about how to improve it. Check out this post for more details on performance cdb.reacttraining.com/react-inline.... So the perfect component does exist, and it's already the default component :D

Appreciate all your content just a bit worried that this post may mislead some newer folks :)

Collapse
 
bassemibrahim profile image
Bassem

Thanks for your comment. πŸ™

If you aren’t measuring, you can’t even know if your optimizations are better, and you certainly won’t know if they make things worse!

This totally makes sense! We use PureComponent everywhere where I am working ( It is like a rule ). You got me excited to measure the difference though. I will definitely try to do that in the near future. 😊