React повторно отображает всю функцию при изменении состояния

#reactjs #react-suspense

#reactjs #реакция-приостановка

Вопрос:

Я рассматриваю реализацию экрана загрузки, который проверяет, загружены ли все компоненты, но наткнулся на этот странный шаблон. С помощью приведенного ниже кода я запускаю App false консоль для запуска, через 2000 мс, когда функция delayHTML возвращает данные обратно, я получаю LoadComponent mount event и App true .

Но затем она возвращается в резервный режим ожидания, и я получаю еще 2000 мс, где снова появляются сообщения LoadComponent mount event и App true , что выглядит как 2-й рендеринг. Как я могу этого избежать?

 function App() {
  const [fullLoadState, setfullLoadState] = useState(false);
  
  console.lo&("App "   fullLoadState)

  eventBus.on("FullyLoaded", (data) =&&t; setfullLoadState(true));

  return (
    <div&&t;
      <Suspense fallback='Fallback'&&t;
        <LoadComponent resource={delayHTML(2000)}/&&t;
      </Suspense&&t;
      <p&&t;{fullLoadState ? null : "Site not fully loaded" }</p&&t;
    </div&&t;
  );
}

function LoadComponent({resource}){
  useEffect(()=&&t; {
    console.lo& ('LoadComponent mount event')
    eventBus.dispatch("FullyLoaded", {messsa&e: 'some messa&e'});
  })
  const html = resource.read();
  return html;
}

export default App;
  

EventBus — это просто EventListener. delayHTML приостанавливается до достижения 2000 мс, чтобы вернуть текстовое значение.

Комментарии:

1. Оба сообщения являются ожидаемым поведением. Изменение состояния вызывает повторный запуск компонента (приложения). useEffect без зависимостей также выполняется при каждом рендеринге.

2. Также вы никогда не должны выполнять побочные эффекты (например, подписки) при рендеринге. Переместите этот код в useEffect с соответствующей функцией очистки. eventBus.on("FullyLoaded", (data) =&&t; setfullLoadState(true));

Ответ №1:

В зависимости от того, как react отображает свой компонент, вы можете создать переменную, назначить delayHTML и использовать ее.

Например,

 const delayFunc = delayHTML(2000);
...
<LoadComponent resource={delayFunc}/&&t;
  

Это должно сработать.

Комментарии:

1. Попробовал вариант этого — const delayFunc = useState(delayHTML(2000)). Это несколько сработало — больше нет второй загрузки для резервного копирования suspense, но LoadComponent mount event дважды регистрировалось в консоли. В консоли также отображается предупреждение: Cannot update a component ( App ) while renderin& a different component ( LoadComponent )

2. Можете ли вы поделиться телом функции delayHtml?

3. Я думаю, Юрий может быть прав — изменения состояния заставляют React снова запускать функцию render(). функция delayHTML(ms) { return (wrapPromise(new Promise(resolve =&&t; { setTimeout(() =&&t; { resolve(‘abc’)}, ms ) }))) }

4. Да, изменения состояния заставляют React снова запускать метод визуализации. Именно так разработан React.

5. Спасибо! Поддержано, но здесь это не отображается. Есть идеи по поводу предупреждающего сообщения? Это ни на что не влияет, но, возможно, React не подходит для выполнения каких-либо действий.

Ответ №2:

Можете ли вы попробовать изменить свой useEffect на это:

   useEffect(()=&&t; {
    console.lo& ('LoadComponent mount event')
    eventBus.dispatch("FullyLoaded", {messsa&e: 'some messa&e'});
  }, [])
  

Комментарии:

1. Пробовал это, и кажется, что разницы нет

2. Таким образом, вы можете попробовать что-то еще. Измените вашу функцию EventBus.on на эту —&&t; EventBus.on(«Полностью загруженный», (данные) =&&t; if(!fullLoadState) setfullLoadState(true));