TL; DR
Как родительский компонент может знать, когда закончился рендеринг каждого дочернего компонента, и DOM виден пользователю с его самой последней версией?
Допустим, у меня component A
есть дочерний Grid
компонент, состоящий из 3x3
компонентов внука. Каждый из этих компонентов внука извлекает данные из конечной точки API успокоительного и отображает себя, когда данные становятся доступными.
Я хотел бы, чтобы покрыть всю область Component A
с loader
заполнителем, будет открыта только тогда , когда последние из компонентов в сетке имеют сгружены данные успешно, и вынес его, таким образом, что это уже на DOM и может быть просмотрено.
Пользовательский опыт должен быть очень плавным переходом от «загрузчика» к полностью заполненной сетке без мерцания.
Моя проблема в том, чтобы точно знать, когда открыть компоненты под загрузчиком.
Есть ли механизм, на который я могу положиться, чтобы сделать это с абсолютной точностью? Я не жестко прописываю ограничение по времени для загрузчика. Как я понимаю, полагаться на ComponentDidMount
каждого ребенка также ненадежно, поскольку на самом деле он не гарантирует, что компонент полностью виден пользователю во время вызова.
Чтобы отогнать вопрос еще дальше:
У меня есть компонент, который отображает некоторые данные. После того, как он инициализирован, у него его нет, поэтому
componentDidMount
он обращается к конечной точке API для него. Как только он получает данные, он меняет свое состояние, чтобы отражать их. Понятно, что это вызывает повторную визуализацию конечного состояния этого компонента. Мой вопрос заключается в следующем: как я узнаю, когда этот повторный рендеринг произошел и отразился на DOM пользователя? Этот момент времени! = Момент времени, когда состояние компонента изменилось и теперь содержит данные.
ComponentDidMount
я используюaxios
для извлечения данных. когда данные поступают, я меняю состояние того компонента, который вызывает рендеринг данных. Теоретически, 8 дочерних компонентов могут быть получены в течение 3 секунд, а последний займет 15 секунд ...Ответы:
В React есть две ловушки жизненного цикла, которые вызываются после рендеринга DOM компонента:
Для вашего случая использования ваш родительский компонент P заинтересован , когда N дочерние компоненты имеют каждый удовлетворяется некоторое условие X . X может быть определен как последовательность:
Комбинируя состояние компонента и используя
componentDidUpdate
ловушку, вы можете узнать, когда последовательность завершилась и ваш компонент соответствует условию X.Вы можете отслеживать, когда ваша асинхронная операция завершилась, установив переменную состояния. Например:
После установки состояния React вызовет
componentDidUpdate
функцию компонентов . Сравнивая текущие и предыдущие объекты состояния в этой функции, вы можете сообщить родительскому компоненту о том, что ваша асинхронная операция завершилась и состояние вашего нового компонента было визуализировано:В вашем P-компоненте вы можете использовать счетчик для отслеживания того, сколько потомков содержательно обновили:
Наконец, зная длину N, вы можете знать, когда произошли все значимые обновления, и действовать соответствующим образом в методе рендеринга P :
источник
Я бы настроил его так, чтобы вы полагались на глобальную переменную состояния, чтобы сообщить своим компонентам, когда нужно визуализировать. Redux лучше для этого сценария, когда многие компоненты общаются друг с другом, и вы упомянули в комментарии, что иногда используете его. Поэтому я набросаю ответ, используя Redux.
Вы должны переместить вызовы API в родительский контейнер
Component A
. Если вы хотите, чтобы ваши внуки отображались только после завершения вызовов API, вы не можете оставить эти вызовы API в самих внуках. Как можно выполнить вызов API из компонента, который еще не существует?После выполнения всех вызовов API вы можете использовать действия для обновления глобальной переменной состояния, содержащей набор объектов данных. Каждый раз, когда данные получены (или обнаружена ошибка), вы можете отправить действие, чтобы проверить, полностью ли заполнен ваш объект данных. Как только он будет полностью заполнен, вы можете обновить
loading
переменнуюfalse
и условно отобразить вашGrid
компонент.Так, например:
Ваш редуктор будет удерживать объект глобального состояния, который скажет, все ли готово к работе или нет:
В ваших действиях:
В стороне
Если вы действительно женаты на идее, что ваши вызовы API живут внутри каждого внука, но вся сетка внуков не рендерится, пока все вызовы API не будут завершены, вам придется использовать совершенно другое решение. В этом случае ваши внуки должны будут отображаться с самого начала, чтобы сделать их вызовы, но иметь класс css
display: none
, который изменяется только после того, как глобальная переменная состоянияloading
помечена как ложная. Это также выполнимо, но в некотором роде помимо точки Реагирования.источник
Вы могли бы потенциально решить эту проблему с помощью React саспенса.
Предостережение заключается в том, что не следует делать приостановку за деревом компонентов, которое выполняет рендеринг (т. Е. Если ваш компонент запускает процесс рендеринга, то, по моему опыту, не рекомендуется приостанавливать этот компонент), поэтому Вероятно, лучшая идея начать запросы в компоненте, который отображает ячейки. Что-то вроде этого:
Теперь, совсем как Suspense сочетается с Redux, я не уверен. Вся идея этой (экспериментальной!) Версии Suspense заключается в том, что вы запускаете выборку сразу во время цикла рендеринга родительского компонента и передаете объект, который представляет выборку, дочерним элементам. Это избавляет вас от необходимости иметь какой-либо объект Barrier (который вам понадобится в других подходах).
Я скажу, что не думаю, что ожидание до тех пор, пока все будет собрано для отображения чего-либо, - это правильный подход, потому что тогда интерфейс будет медленным, как самое медленное соединение, или может вообще не работать!
Вот остальная часть отсутствующего кода:
И песочница: https://codesandbox.io/s/falling-dust-b8e7s
источник
Прежде всего, жизненный цикл может иметь метод асинхронного ожидания.
Что нам нужно знать о
componentDidMount
иcomponentWillMount
,На мой взгляд, достаточно просто реализовать их с использованием нормального жизненного цикла.
Материал-Пользовательский интерфейс CircularProgress
Так как дочерний повторный рендеринг заставляет родителя делать то же самое, поймать его
didUpdate
было бы хорошо.И, так как он вызывается после рендеринга, страницы не должны изменяться после этого, если вы установили функцию проверки в качестве своего требования.
Мы используем эту реализацию в нашей программе, у которой есть API, вызывающий 30-х годов, чтобы получить ответ, насколько я вижу, все работало хорошо.
источник
Как вы делаете вызов апи в
componentDidMount
, когда вызов API будет решить , вы будете иметь данные ,componentDidUpdate
как это жизненный цикл будет проходить мимо ВасprevProps
иprevState
. Так что вы можете сделать что-то вроде ниже:Если вы хотите знать это до того, как компонент будет отрендерен, вы можете использовать
getSnapshotBeforeUpdate
.https://reactjs.org/docs/react-component.html#getsnapshotbeforeupdate .
источник
Есть несколько подходов, которые вы можете использовать:
источник