Как получить доступ к избыточному хранилищу при использовании ReactDOM.render к элементу рендеринга? - PullRequest
3 голосов
/ 14 января 2020

Я создал компонент с вкладками, который отображает 8 элементов вкладок. Каждая вкладка связана с компонентом, который выполняет очень дорогие операции. Рендеринг всех 8 компонентов при монтировании компонентов сильно влияет на производительность.

Чтобы оптимизировать производительность, вместо рендеринга всех 8 компонентов одновременно, я отобразил свой массив вкладок и отобразил пустой заполнитель div, который будет лениво загружать компонент в пустой div впервые каждую вкладку нажмите. Я получил это успешно работает, однако после монтирования каждого компонента вкладки у меня нет доступа к хранилищу приставок.

Может кто-нибудь объяснить, почему и посоветовать, как мне это решить?

Спасибо

Пример кода

const handleTabClick = tabIndex => event => {
   setSelectedTab(tabIndex);
   renderContentBlock(tabIndex);
};

const renderContentBlock = tabIndex => {
  const updatedTabs = [...tabs];

  // no need to rerender content block if already rendered
  if (updatedTabs[tabIndex].rendered) return;

  updatedTabs[tabIndex].rendered = true;

  ReactDOM.render(
    <LazyLoad component={updatedTabs[tabIndex].component} />,
    document.getElementById(updatedTabs[tabIndex].name)
  );

  setTabs(updatedTabs);
};

{
  tabs.map((tab, index) => (
    <div
        key={index}
        onClick={handleTabClick(index)}
    >
      {tab.name}
    </div>

  ))
}

{ 
  tabs.map((tab, index) => (
   <div
     key={index}
     id={tab.name}
     ref={el => (expandedContentBlockRef.current[index] = el)}
   /></div>
  ))
}

1 Ответ

2 голосов
/ 14 января 2020

Когда вы используете ReactDOM.render() для визуализации компонента на узле DOM вне дерева React, он не является частью исходного дерева и не имеет доступа к контексту. Это означает, что он не может быть подключен к хранилищу резервов, которое управляется через контекст.

Возможным решением было бы использование ReactDOM.createPortal(), которое поддерживает соединение с деревом при рендеринге контента на другой узел DOM:

ReactDOM.createPortal(
  <LazyLoad component={updatedTabs[tabIndex].component} />,
  document.getElementById(updatedTabs[tabIndex].name)
);

Тем не менее, ваша главная задача - ленивая загрузка / рендеринг вкладки. Поскольку может отображаться только содержимое одной вкладки, вам не нужно отображать их все сразу. Кроме того, в реагировании есть встроенный механизм кодирования разбиения / отложенной загрузки , который вы можете использовать для своего случая.

Пример (не тестировался):

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

const tabs = [{ title: 'TabA', path: 'tabAFilePath' }, { title: 'TabB', path: 'tabBFilePath' }, ...] // an array of paths to Component's files in your code
  .map(o => ({ ...o, Page: lazy(() => import(o.path) }))

const Tab = ({ tab, setTab }) => {
  const setCurrentTab = useCallback(() => setTab(tab), [tab]);

  return (
    <div onClick={setCurrentTab}>{tab.title}</div>
  );
};

const Tabs = () => {
  const [current, setTab] = useState(tabs[0]);

  const { Page } = current;

  return (
    <div>{tabs.map(tab => <Tab tab={tab} setTab={setTab} />)}</div>

    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <Page />
      </Suspense>
    </div>
  );
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...