React.memo is similar to PureComponent when working with class components. This feature new to React 16 will not allow a functional component to render if its props hasn’t changed.
Tyler Clark: [0:00] Here's the Products page in my app. It renders many individual product components that displays info like name, color, and price. For educational purposes, let's add some state to this top-level Products component.
[0:15] Here is the code for the Products component. It has all of the state necessary in the product components that house the price and stuff. Underneath here, let's go ahead and add a useState hook. I'm just going to say buttonClicked and setButtonClicked with initial value of false to begin with.
[0:35] Now, inside of our code further down, let's go ahead and add some button HTML or JSX down here to click on to change that state. We'll do it just underneath the Products title here.
[0:49] With that in there and we go back to see what it looks like, you'll notice that we have a State change button here that switches back and forth to State changed and Change text. Pretty self-explanatory here, just a simple ternary that switches it back and forth, depending on the state of the buttonClicked state.
[1:10] Now, you'll notice something interesting here. As I click on Change text and switch back and forth, notice the delay in the click. Now it is very subtle, but you can notice that there is about a half of a second it takes to switch between Change text and State changed.
[1:30] This is not ideal, right? We would expect this to be instant, a quick change back and forth. We can easily see what's happening by running a test. Inside of this ProductCard component, you notice that it's being mapped over off products and pumping out these product cards.
[1:48] If we go inside of this components and add a console log just inside of the body of this functional component, and then refresh the page, you'll notice that we have 189 product cards. As we change the state, every single 189 product card is then re-rendered, which is why the delay happens here.
[2:15] You'll notice that until the console logs all fire, our state doesn't actually change here in the text. This is obviously a pretty terrible experience because the changing of the simple state that we added at the top has nothing to do with the product cards.
[2:32] The products are exactly the same with each change of state. There's no need for them to re-render whenever we're changing state up higher in the JSX.
[2:44] How do we get these products to not re-render unless they actually need to? Back inside of ProductCard, the way that we'll solve this is actually wrapping the entire component with React.memo. This is a higher-order component, so we'll wrap the entire ProductCard component with this, and then save and take a look.
[3:06] On the initial load, of course, we're going to get the initial ProductCard rendered. If we clear and then change the State changed, notice that we are not getting any console logs. Look at the speed in which this changes. It's instant because it's not re-rendering on each time.
[3:23] A couple things to know about React.memo, it only works for functional components and not classical ones. Second of all, it only does a shallow compare against the props that it gets.
[3:35] If you have a prop that's an object that has nested objects within it or arrays that have objects with nested objects, it's not going to do a deep comparison on all the properties within those objects and values.
[3:48] In order to do a custom comparison, you can pass React.memo a custom comparison function. That's going to go as the second argument. Down here at the bottom of our React.memo function, we would just pass in a conditional comparison function of our own making.
[4:07] The final thing to be aware of is, as stated in the React docs, "React.memo only checks for prop changes." If your function component uses a useState, useReducer, or useContext hook, it will still re-render when state or context change. It's something to keep aware of.
[4:26] If you're using React.memo and it doesn't work on your component and you're following the other rules, like it being a functional component, double check to make sure that it's not using useState or these other two hooks inside of its implementation.