will react helmet componentwillmount componentdidmount component await async reactjs asynchronous react-native

reactjs - componentwillmount - react helmet ssr



¿Está bien usar async componentDidMount()? (7)

Actualizar:

(Mi versión: React 16, Webpack 4, Babel 7):

Al usar Babel 7 descubrirás:

Usando este patrón ...

async componentDidMount() { try { const res = await fetch(config.discover.url); const data = await res.json(); console.log(data); } catch(e) { console.error(e); } }

te encontrarás con el siguiente error ...

Error de referencia no capturado: regeneratorRuntime no está definido

En este caso necesitará instalar babel-plugin-transform-runtime

https://babeljs.io/docs/en/babel-plugin-transform-runtime.html

Si por alguna razón no desea instalar el paquete anterior (babel-plugin-transform-runtime), entonces querrá apegarse al patrón Promise ...

componentDidMount() { fetch(config.discover.url) .then(res => res.json()) .then(data => { console.log(data); }) .catch(err => console.error(err)); }

¿Está utilizando componentDidMount() como una función asíncrona una buena práctica en React Native o debería evitarlo?

Necesito obtener información de AsyncStorage cuando se monta el componente, pero la única forma que sé para que sea posible es hacer que el componentDidMount() funcione de forma asíncrona.

async componentDidMount() { let auth = await this.getAuth(); if (auth) this.checkAuth(auth); }

¿Hay algún problema con eso y hay otras soluciones a este problema?


Comencemos señalando las diferencias y determinando cómo podría causar problemas.

Aquí está el código del método de ciclo de vida asincrónico y "sincronizado" del componentDidMount() :

// This is typescript code componentDidMount(): void { /* do something */ } async componentDidMount(): Promise<void> { /* do something */ /* You can use "await" here */ }

Al mirar el código, puedo señalar las siguientes diferencias:

  1. Las palabras clave async : en mecanografiado, esto es simplemente un marcador de código. Hace 2 cosas:
    • Forzar que el tipo de retorno sea Promise<void> lugar de void . Si especifica explícitamente que el tipo de devolución no es prometedor (por ejemplo, nulo), el mecanografiado le arrojará un error.
    • Le permite usar palabras clave en await dentro del método.
  2. El tipo de retorno se cambia de void a Promise<void>
    • Significa que ahora puedes hacer esto:
      async someMethod(): Promise<void> { await componentDidMount(); }
  3. Ahora puede usar la palabra clave await dentro del método y pausar temporalmente su ejecución. Me gusta esto:

    async componentDidMount(): Promise<void> { const users = await axios.get<string>("http://localhost:9001/users"); const questions = await axios.get<string>("http://localhost:9001/questions"); // Sleep for 10 seconds await new Promise(resolve => { setTimeout(resolve, 10000); }); // This line of code will be executed after 10+ seconds this.setState({users, questions}); return Promise.resolve(); }

Ahora, ¿cómo podrían causar problemas?

  1. La palabra clave async es absolutamente inofensiva.
  2. No puedo imaginar ninguna situación en la que necesite hacer una llamada al método componentDidMount() , por lo que el tipo de retorno Promise<void> es inofensivo.

    Llamar a un método que tenga el tipo de retorno Promise<void> sin await palabra clave no hará ninguna diferencia de llamar a uno que tenga el tipo de retorno de void .

  3. Dado que no hay métodos de ciclo de vida después de que componentDidMount() retrase su ejecución parece bastante seguro. Pero hay una trampa.

    Digamos, lo anterior this.setState({users, questions}); sería ejecutado después de 10 segundos. En medio del tiempo de retraso, otro ...

    this.setState({users: newerUsers, questions: newerQuestions});

    ... se ejecutaron correctamente y el DOM se actualizó. El resultado fue visible para los usuarios. El reloj siguió marcando y transcurrieron 10 segundos. El retrasado this.setState(...) se ejecutaría y el DOM se actualizaría nuevamente, esa vez con usuarios antiguos y preguntas antiguas. El resultado también sería visible para los usuarios.

=> Es bastante seguro (no estoy seguro acerca del 100%) usar async con el método componentDidMount() . Soy un gran admirador y hasta ahora no he encontrado ningún problema que me dé demasiado dolor de cabeza.


Creo que está bien siempre y cuando sepas lo que estás haciendo. Pero puede ser confuso porque async componentDidMount() aún puede ejecutarse después de que componentWillUnmount haya ejecutado y el componente se haya desmontado.

También es posible que desee iniciar tareas sincrónicas y asincrónicas dentro de componentDidMount . Si componentDidMount era asíncrono, tendría que poner todo el código síncrono antes de la primera await . Puede que no sea obvio para alguien que el código anterior a la primera await ejecuta sincrónicamente. En este caso, probablemente mantendría el componentDidMount sincrónico, pero lo llamaría métodos de sincronización y asíncrono.

Ya sea que elija async componentDidMount() vs sync componentDidMount() llamando a métodos async , debe asegurarse de limpiar todos los escuchas o métodos asincrónicos que aún puedan estar ejecutándose cuando el componente se desmonta.


Cuando usa componentDidMount sin palabra clave async , el documento dice esto:

Puede llamar a setState () inmediatamente en componentDidMount (). Activará una representación adicional, pero sucederá antes de que el navegador actualice la pantalla.

Si usa el async componentDidMount perderá esta capacidad: se producirá otro procesamiento DESPUÉS de que el navegador actualice la pantalla. Pero, si estás pensando en usar asíncrono, como buscar datos, no puedes evitar que el navegador actualice la pantalla dos veces. En otro mundo, no es posible PAUSAR componentDidMount antes de que el navegador actualice la pantalla


En realidad, la carga asíncrona en ComponentDidMount es un patrón de diseño recomendado a medida que React se aleja de los métodos de ciclo de vida heredados (componentWillMount, componentWillReceiveProps, componentWillUpdate) y pasa a Async Rendering.

Esta publicación de blog es muy útil para explicar por qué esto es seguro y para proporcionar ejemplos de carga asíncrona en ComponentDidMount:

https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html


He realizado algunas investigaciones y he encontrado una diferencia importante: React no procesa errores de los métodos asíncronos del ciclo de vida.

Entonces, si escribes algo como esto:

componentDidMount() { throw new Error(''I crashed!''); }

entonces su error será detectado por el límite de errores , y puede procesarlo y mostrar un mensaje elegante.

Si cambiamos el código así:

async componentDidMount() { throw new Error(''I crashed!''); }

que es equivalente a esto:

componentDidMount() { return Promise.reject(new Error(''I crashed!'')); }

entonces su error será tragado en silencio . La culpa es tuya, reacciona ...

Entonces, ¿cómo procesamos los errores que? La única forma parece ser una captura explícita como esta:

componentDidMount() { try { await myAsyncFunction(); } catch(error) { //... } }

o así:

componentDidMount() { myAsyncFunction() .catch(()=> { //... }); }

Si aún queremos que nuestro error enriquezca el límite de error, puedo pensar en el siguiente truco:

  1. Detecte el error, haga que el controlador de errores cambie el estado del componente
  2. Si el estado indica un error, tírelo desde el método de render .

Ejemplo:

class BuggyComponent extends React.Component { constructor(props) { super(props); this.state = { error: null }; } buggyAsyncfunction(){ return Promise.reject(new Error(''I crashed async!''));} async componentDidMount() { try { await this.buggyAsyncfunction(); } catch(error) { this.setState({error: error}); } } render() { if(this.state.error) throw this.state.error; return <h1>I am OK</h1>; } }


Tu código está bien y es muy legible para mí. Vea este artículo de Dale Jefferson donde muestra un componentDidMount asincrónicoDidMount y se ve muy bien también.

Pero algunas personas dirían que una persona que lee el código puede asumir que React hace algo con la promesa devuelta.

Entonces la interpretación de este código y si es una buena práctica o no es muy personal.

Si quieres otra solución, puedes usar promises . Por ejemplo:

componentDidMount() { fetch(this.getAuth()) .then(auth => { if (auth) this.checkAuth(auth) }) }