Phoen1xx
@Phoen1xx

Как заставить react перерисовывать только один элемент при обновлении state?

Всем привет. Подскажите пожалуйста, я создаю массив объектов в state, и генерирую при помощи map дочерние компоненты, и при изменении одного поля, ререндерится все заново. Есть какой-то способ это оптимизировать? Мне казалось что именно для этого указывается поле key, но оно не помогает.
Вот пример кода:
let myData = [
    { id: 1, data: 'Foo' },
    { id: 2, data: 'Bar' }
]

export default function Test(){
    let [items, setItem] = useState(myData);

    let setNewItemData = (itemId, data) => {
        let newItems = items.map(item => {
            if(item.id !== itemId){
                return item;
            }

            return { ...item, data }
        });

        setItem(newItems)
    }

    console.log('Render main Component');

    return (
        <>
            {
                items.map(item => {
                    return (
                        <MyItem key={item.id} item={item} setNewItemData={setNewItemData}></MyItem>
                    )
                })
            }
        </>
    )

}

export default function MyItem({ item, setNewItemData }) {
    console.log('Render MyItem');

    return (
        <button onClick={ () => { setNewItemData(item.id, 'New value') } }>{item.data}</button>
    )
}
  • Вопрос задан
  • 1655 просмотров
Решения вопроса 2
profesor08
@profesor08 Куратор тега JavaScript
При каждом вызове setNewItemData у тебя получается новый массив items. Который ты пихаешь в setItem. При каждом вызове setItem, выполнится вся твоя функция, а значит и items.map, и заново отрендерится каждый из MyItem. Если хочешь что рисовался только MyItem, то модифицируй его внутренний стейт, а не стейт родителя.

const Item = ({ item }) => {
  const [item, setItem] = useState(itemProp);

  const updateItem = useCallback(() => {
    setItem((item) => ({
      ...item,
      count: item.count + 1
    }));
  }, []);

  return (
    <div onClick={updateItem}>
      {item.title} {item.count}
    </div>
  );
};
Ответ написан
Alexandroppolus
@Alexandroppolus
кодир
Использовать React.memo для MyItem

export default const MyItem = React.memo(({ item, setNewItemData }) => {
   ....
});


в компоненте Test функцию setNewItemData обернуть в useCallback, чтобы она была постоянной. Для этого внутри неё использовать setItems с передачей в него функции, чтобы setNewItemData не зависело от items

let [items, setItems] = useState(myData);

    const setNewItemData = useCallback((itemId, data) => {
        setItems((items) => {
            return items.map(item => {
                if (item.id !== itemId) {
                    return item;
                }
    
                return {...item, data}
            });
        });
    }, [setItems]);
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
w13vitaliy
@w13vitaliy
self-taught developer since 2020
При изменение родительского компонента он рендерит все дочерние елементы
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
25 апр. 2024, в 12:20
15000 руб./за проект
25 апр. 2024, в 12:08
300 руб./за проект
25 апр. 2024, в 11:49
25000 руб./за проект