Как перестать реагировать компонент повторного рендеринга, если часть состояния меняется? - PullRequest
0 голосов
/ 29 марта 2020

Есть ли способ остановить повторный рендеринг реакции, если изменяется только часть состояния?

Проблема в том, что каждый раз, когда я нахожу на маркер всплывающее окно, открывается или закрывается, и это заставляет все маркеры перерисовать, даже если mystate не меняется, только состояние activePlace меняется. console.log(myState); запускается каждый раз, когда я наводю курсор на маркер.

Я пытался использовать хук useMemo, но не мог понять, как его использовать. Любая помощь?

Вот мой код:

import React, { useEffect, useState } from 'react';
import { Map, TileLayer, Marker, Popup } from 'react-leaflet';
import axios from 'axios';
import { v4 as uuidv4 } from 'uuid';
import { Icon } from 'leaflet';

const myicon = new Icon({
  iconUrl: './icon.svg',
  iconSize: [20, 20]
});

const MyMap = () => {
  const [myState, setMyState] = useState(null);
  const [activePlace, setActivePlace] = useState(null);

  const getData = async () => {
    let response = await axios
      .get('https://corona.lmao.ninja/v2/jhucsse')
      .catch(err => console.log(err));

    let data = response.data;
    setMyState(data);

    // console.log(data);
  };

  useEffect(() => {
    getData();
  }, []);

  if (myState) {
    console.log(myState);
    return (
        <Map
          style={{ height: '100vh', width: '100vw' }}
          center={[14.561, 17.102]}
          zoom={1}
        >
          <TileLayer
            attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>'
            url={
              'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png'
            }
          />

          {myState.map(country => {
            return (
              <Marker
                key={uuidv4()}
                position={[
                  country.coordinates.latitude,
                  country.coordinates.longitude
                ]}
                onmouseover={() => {
                  setActivePlace(country);
                }}
                onmouseout={() => {
                  setActivePlace(null);
                }}
                icon={myicon}
              />
            );
          })}

          {activePlace && (
            <Popup
              position={[
                activePlace.coordinates.latitude,
                activePlace.coordinates.longitude
              ]}
            >
              <div>
                <h4>Country: {activePlace.country}</h4>
              </div>
            </Popup>
          )}
        </Map>
    );
  } else {
    return <div>Loading</div>;
  }
};

export default MyMap;

1 Ответ

3 голосов
/ 29 марта 2020

Эта строка является вашей проблемой:

key={uuidv4()}

Почему вы создаете уникальный идентификатор для каждого рендера? Смысл идентификатора в том, что он остается неизменным между рендерами, поэтому React знает, что ему не нужно перерисовывать этот компонент в DOM.

Существует два этапа, которые происходят при изменении состояния: фаза рендеринга и фаза фиксации .

Фаза рендеринга происходит первой, и именно здесь все ваши компоненты выполняют свои функции рендеринга (то есть весь компонент в случай функционального компонента). Возвращаемый JSX превращается в узлы DOM и добавляется в виртуальный DOM . Это очень эффективно и НЕ то же самое, что ре-рендеринг фактического DOM.

На этапе фиксации новый виртуальный DOM сравнивается с реальным DOM, и любые различия, обнаруженные в реальном DOM, будут повторно

Цель React - ограничить повторные рендеры реального DOM. Это не ограничивает пересчет виртуального DOM.

Это означает, что для всего этого компонента вполне нормально запускать свой цикл рендеринга при изменении activePlace.

Однако, поскольку вы даете совершенно новый идентификатор каждому country на каждом цикле рендеринга, виртуальный DOM считает, что каждая страна изменилась (он использует идентификаторы для сравнения предыдущих значений DOM), поэтому все страны в реальном DOM также будут перерисованы, поэтому, вероятно, вы сталкиваетесь с проблемами с задержкой.

Идентификатор должен быть связан со страной, например, с кодом страны, а не просто случайный UUID. Если вы используете случайные UUID, сохраните их вместе со страной, чтобы всегда использовался один и тот же.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...