Jacob
Jacob

Reputation: 265

How do we stop the re-rendering of A and B in React?

enter image description here

import React, { useState, useEffect, useCallback } from "react";

export const Root = () => {
  const [items, setItems] = useState(["A", "B"]);

  const _onClick = useCallback( item => {
    return () =>alert(item);
  },[]);
  return (
    <>
      <button onClick={() => setItems(["A", "B", "C"])}>Button</button>
      {items.map((item, index) => (
        <Item key={index} item={item} onClick={_onClick(item)} />
      ))}
    </>
  );
};

const Item = React.memo(({ item, onClick }) => {
  useEffect(() => {
    console.log("Item: ", item);
  });
  return <button onClick={onClick}>{item}</button>;
});

How do we stop the re-rendering of A and B? The result I want is to be a memo on the console when the button is pressed and "Item: C".

Upvotes: 1

Views: 50

Answers (2)

Puckwang
Puckwang

Reputation: 434

Because onClick of <Item/> is new every time it is rendered, it will cause A and B to re-render.

You can use React.memo second parameter to check, for example:

const Item = React.memo(({ item, onClick }) => {
    // ...
    return <button onClick={onClick}>{item}</button>;
}, (prevProps, nextProps) => {
    console.log(Object.is(prevProps.onClick, nextProps.onClick)); // console: false
});

More see doc.


In your code, _onClick(item) will return new callback every render.

<Item key={index} item={item} onClick={_onClick(item)} />

You can change _onClick to this:

const _onClick = useCallback(item => alert(item), []);

Next, pass _onClick to Item, and change how button's onClick is executed.

<Item key={index} item={item} onClick={_onClick} />

//...

<button onClick={() => onClick(item)}>{item}</button>

The full code is as follows:

import React, { useCallback, useState } from 'react';

export const Root = () => {
    const [items, setItems] = useState(['A', 'B']);

    const _onClick = useCallback(item => alert(item), []);
    return (
        <>
            <button onClick={() => setItems(['A', 'B', 'C'])}>Button</button>
            {items.map((item, index) => (
                <Item key={index} item={item} onClick={_onClick} />
            ))}
        </>
    );
};

const Item = React.memo(({ item, onClick }) => {
    useEffect(() => {
        console.log("Item: ", item);
    });
    return <button onClick={() => onClick(item)}>{item}</button>;
});

Upvotes: 1

Anuj Shah
Anuj Shah

Reputation: 571

You were calling _onClick from the wrong place. Rather than calling on the Item component, you should call on the button's onClick event.

Check these working Code Sandbox.

Upvotes: 0

Related Questions