Является ли использование componentDidMount()
асинхронной функции хорошей практикой в React Native или мне следует избегать этого?
Мне нужно получить некоторую информацию о том, AsyncStorage
когда компонент монтируется, но единственный известный мне способ сделать это возможным - сделать componentDidMount()
функцию асинхронной.
async componentDidMount() {
let auth = await this.getAuth();
if (auth)
this.checkAuth(auth);
}
Есть ли здесь какие-либо проблемы и есть ли другие решения этой проблемы?
reactjs
asynchronous
react-native
Mirakurun
источник
источник
Ответы:
Начнем с того, что укажем на различия и определим, как это может вызвать проблемы.
Вот код метода
componentDidMount()
жизненного цикла async и "sync" :Посмотрев на код, я могу отметить следующие отличия:
async
ключевые слова: В машинописи, это просто код маркера. Он делает 2 вещи:Promise<void>
вместоvoid
. Если вы явно укажете, что тип возвращаемого значения не является обещанием (например, void), машинописный текст выдаст вам ошибку.await
ключевые слова внутри метода.void
наPromise<void>
async someMethod(): Promise<void> { await componentDidMount(); }
Теперь вы можете использовать
await
ключевое слово внутри метода и временно приостановить его выполнение. Как это:Итак, как они могли вызвать проблемы?
async
Ключевое слово является абсолютно безвредным.Я не могу представить себе ситуацию, в которой вам нужно вызвать
componentDidMount()
метод, поэтому возвращаемый типPromise<void>
тоже безвреден.Вызов метода с типом возврата
Promise<void>
безawait
ключевого слова не будет иметь никакого значения от вызова метода с типом возвратаvoid
.Поскольку нет методов жизненного цикла после
componentDidMount()
отсрочка его выполнения кажется довольно безопасной. Но тут есть подводный камень.Скажем, вышеуказанное
this.setState({users, questions});
будет выполнено через 10 секунд. Посреди времени задержки еще один ...this.setState({users: newerUsers, questions: newerQuestions});
... были успешно выполнены, и DOM обновлен. Результат был виден пользователям. Часы продолжали идти, и прошло 10 секунд. Затем
this.setState(...)
будет выполнено отложенное выполнение, и DOM будет обновляться снова, на этот раз с учетом старых пользователей и старых вопросов. Результат также будет виден пользователям.=> Это довольно безопасно (я не уверен на 100%) использовать
async
сcomponentDidMount()
методом. Я его большой поклонник и пока не сталкивался с проблемами, которые вызывают у меня слишком много головной боли.источник
setState()
всегда связано с небольшим риском. Мы должны действовать осторожно.isFetching: true
состояния компонента. Я использовал это только с redux, но я полагаю, что это полностью справедливо с управлением состоянием только для реакции. Хотя на самом деле это не решает проблему обновления одного и того же состояния где-то еще в коде ...isFetching
флаговое решение довольно распространено, особенно когда мы хотим воспроизвести некоторые анимации во внешнем интерфейсе, ожидая ответа (isFetching: true
).Обновление от апреля 2020 года: проблема, похоже, исправлена в последней версии React 16.13.1, см. Этот пример песочницы . Спасибо @abernier за указание на это.
Я провел небольшое исследование и обнаружил одно важное отличие: React не обрабатывает ошибки асинхронных методов жизненного цикла.
Итак, если вы напишете что-то вроде этого:
тогда ваша ошибка будет поймана границей ошибки , и вы сможете обработать ее и отобразить изящное сообщение.
Если мы изменим код так:
что эквивалентно этому:
тогда ваша ошибка будет молча проглочена . Позор тебе, Реагировать ...
Итак, как мы обрабатываем ошибки? Кажется, единственный способ - это явный улов:
или вот так:
Если мы по-прежнему хотим, чтобы наша ошибка достигла границы ошибки, я могу подумать о следующем трюке:
render
методаПример:
источник
Ваш код прекрасен и очень удобочитаем для меня. См. Эту статью Дейла Джефферсона, где он показывает пример асинхронности
componentDidMount
и тоже выглядит очень хорошо.Но некоторые люди скажут, что человек, читающий код, может предположить, что React что-то делает с возвращенным обещанием.
Так что интерпретация этого кода и то, является ли это хорошей практикой, очень личное.
Если вам нужно другое решение, вы можете использовать обещания . Например:
источник
async
функцию сawait
s внутри ...?(async () => { const data = await fetch('foo'); const result = await submitRequest({data}); console.log(result) })()
wherefetch
иsubmitRequest
- это функции, возвращающие обещания.Когда вы используете
componentDidMount
безasync
ключевого слова, документ говорит следующее:Если вы используете,
async componentDidMount
вы потеряете эту способность: другой рендеринг произойдет ПОСЛЕ обновления экрана браузером. Но я думаю, если вы думаете об использовании асинхронного режима, например о получении данных, вы не можете избежать, что браузер обновит экран дважды. В другом мире невозможно ПРИОСТАНОВИТЬ componentDidMount до того, как браузер обновит экранисточник
Обновить:
(Моя сборка: React 16, Webpack 4, Babel 7):
При использовании Babel 7 вы обнаружите:
Используя этот шаблон ...
вы столкнетесь со следующей ошибкой ...
Uncaught ReferenceError: регенератор Время выполнения не определено
В этом случае вам нужно будет установить babel-plugin-transform-runtime.
https://babeljs.io/docs/en/babel-plugin-transform-runtime.html
Если по какой-то причине вы не хотите устанавливать указанный выше пакет (babel-plugin-transform-runtime), вам следует придерживаться шаблона Promise ...
источник
Я думаю, это нормально, если ты знаешь, что делаешь. Но это может сбивать с толку, потому что
async componentDidMount()
может все еще работать послеcomponentWillUnmount
запуска и размонтирования компонента.Вы также можете запускать внутри синхронные и асинхронные задачи
componentDidMount
. Если быcomponentDidMount
был асинхронный, вам пришлось бы поместить весь синхронный код перед первымawait
. Для кого-то может быть неочевидно, что код до первогоawait
выполняется синхронно. В этом случае я бы, вероятно, сохранилcomponentDidMount
синхронность, но использовал бы методы sync и async.Независимо от того, выбираете ли вы методы вызова
async componentDidMount()
vs sync , вы должны убедиться, что очистили все прослушиватели или асинхронные методы, которые все еще могут работать, когда компонент отключается.componentDidMount()
async
источник
Фактически, асинхронная загрузка в ComponentDidMount является рекомендуемым шаблоном проектирования, поскольку React переходит от устаревших методов жизненного цикла (componentWillMount, componentWillReceiveProps, componentWillUpdate) к асинхронному рендерингу.
Это сообщение в блоге очень полезно для объяснения того, почему это безопасно, и предоставления примеров асинхронной загрузки в ComponentDidMount:
https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html
источник
Мне нравится использовать что-то вроде этого
источник