React приостановка предотвращения мигания запасной блесны

Мне интересно, есть ли хороший способ предотвратить мигание запасного варианта в реакции. Я использую реагирующий маршрутизатор, и проблема в том, что когда компонент приостанавливается, резервный загрузчик мигает очень быстро, и это довольно раздражает. Я видел ответ здесь Реагировать приостановка / ленивая задержка? который будет выглядеть следующим образом:

const Home = lazy(() => {
  return Promise.all([
    import('./components/Home'),
    new Promise(resolve => setTimeout(resolve, 500))
  ]).then(([moduleExports]) => moduleExports);
});

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

Поэтому я думаю, что вопрос в том, нашел ли кто-нибудь хороший способ справиться с этой проблемой. Я действительно хотел бы добавить что-то вроде nprogress на страницу, но не могу понять, как бы я реализовал это с помощью React.suspense. Возможно, мне просто придется вернуться к использованию реагирующей загрузки, но я действительно не хочу, когда реакция идет с практически такой же функциональностью из коробки.

3 ответа

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

Идея проста, просто какое-то время ничего не показывать, потом показывать загрузчик. Итак, скажем, в течение 300 мс ничего не будет отображаться, после задержки он должен отображать (в данном случае) ContentLoaderили все, что вам нравится.

В машинописном виде как lazy-loader.ts

      import { FC, useEffect, useState } from 'react';
import ContentLoader from './content-loader'; // or any spinner component

export interface LazyLoaderProps {
  delay?: number;
}

const LazyLoader: FC<LazyLoaderProps> = ({
  delay = 250,
  ...props
}) => {
  const [show, setShow] = useState(false);

  useEffect(() => {
    const timeout = setTimeout(() => {
      setShow(true);
    }, delay);
    return () => {
      clearTimeout(timeout);
    };
  }, [delay]);

  return show ? <ContentLoader {...props} /> : null;
};

export { LazyLoader as default };

затем используйте так

      import LazyLoader from "./lazy-loader"
// ...
<Suspense fallback={<LazyLoader delay={300} />}>...</Suspense>

Это не задерживает импорт. (что я также считал не оптимальным). Дайте мне знать, если это поможет.

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

ну, это нормальное поведение Suspense, здесь нет ничего общего, вместо этого мы могли бы обмануть точку зрения наших конечных пользователей, скопировав частичный дизайн фона нашей веб-страницы.

      /* style.css */
.main-pane {
   width: '100%',
   height: '100%',
   backgroundColor: #deb887
}
.header-pane {
   width: '100%',
   height: '100%',
   position: 'absolute',
   top: 0,
   backgroundColor: #424242
}
      //EmptyPage.js
import styles from './style.css';
const EmptyPage = () => {
   return (
      <div style={styles['main-pane']}>
         <div style={styles['header-pane']}><div/>
      </div>
   )
}
      //MainPage.js
import styles from './style.css';
const MainPage = () => {
   return (
      <div style={styles['main-pane']}>
         <div style={styles['header-pane']}>HEADER CONTENT<div/>
         BODY CONTENT
      </div>
   )
}
      //App.js
const MainPage = lazy(() => import('./pages/MainPage'))

import EmptyPage from './pages/EmptyPage';
import styles from './style.css';
const App = () => {
   return (
      <Suspense fallback={<EmptyPage/>}>
         <Router>
            ...
            <MainPage/>
         </Router>
      </Suspense>
   )
}

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

import React, { Suspense, lazy } from "react";

const Home = lazy(() => {
  return Promise.all([
    import("./home"),
    new Promise(resolve => setTimeout(resolve, 300))
  ]).then(([moduleExports]) => moduleExports);
});

function FullSpinner() {
  return (
    {/**  full spinner jsx goes here */}
    <div className="full-spinner">
      <p>loading....</p>
    </div>
  )
}

function App() {
  return (
    <div className="App">
      <h1>app component</h1>
      <Suspense fallback={<FullSpinner />}>
        <Home />
      </Suspense>
    </div>
  );
}

Редактировать:

import React, { Suspense, lazy, useState, useEffect } from "react";

const Home = lazy(() => {
  return Promise.all([
    import("./home"),
    new Promise(resolve => setTimeout(resolve, 500))
  ]).then(([moduleExports]) => moduleExports);
});

function FullSpinner() {
  return (
    <div className="full-spinner">
      <p>loading....</p>
    </div>
  );
}

const LazyLoading = ({ delay, loader: Loader, children }) => {
  const [ready, setReady] = useState(false);
  useEffect(() => {
    setTimeout(() => setReady(true), delay);
  }, [delay]);
  return ready ? (
    <Suspense fallback={<Loader />}>{children}</Suspense>
  ) : (
    <Loader />
  );
};

function App() {
  return (
    <div className="App">
      <h1>app component</h1>
      <LazyLoading delay={2000} loader={FullSpinner}>
        <Home />
      </LazyLoading>
    </div>
  );
}
Другие вопросы по тегам