React v16.9.0 y Actualización de la Hoja de Ruta

August 08, 2019 by Dan Abramov and Brian Vaughn

Hoy estamos liberando React 16.9. Contiene varias nuevas funcionalidades, correcciones de defectos, y nuevos avisos de deprecación para ayudar a prepararse para una nueva versión con cambios mayores en el futuro.

Nuevas Deprecaciones

Renombrado de Métodos del Ciclo de Vida Inseguros

Hace más de un año, anunciamos que los métodos inseguros del ciclo de vida estaban siendo renombrados:

  • componentWillMountUNSAFE_componentWillMount
  • componentWillReceivePropsUNSAFE_componentWillReceiveProps
  • componentWillUpdateUNSAFE_componentWillUpdate

React 16.9 no contiene cambios incompatibles, y los nombres anteriores continuaran funcionando en esta versión. Pero ahora verás una advertencia cuando uses alguno de los nombres anteriores:

Warning: componentWillMount has been renamed, and is not recommended for use.

Como lo sugiere la advertencia, usualmente hay mejores alternativas para cada uno de los métodos inseguros. Sin embargo, a lo mejor no tienes el tiempo para migrar o probar estos componentes. En cuyo caso, recomendamos ejecutar un script de “codemod” que los renombre automáticamente:

cd your_project
npx react-codemod rename-unsafe-lifecycles

(Note que dice npx, no npm. npx es una utilidad que vienen con Node 6+ por defecto.)

Ejecutar este codemod reemplazará los nombres viejos como componentWillMount con los nombres nuevos como UNSAFE_componentWillMount:

Codemod en acción

Los nombres nuevos como UNSAFE_componentWillMount continuarán funcionando tanto en React 16.9 como en React 17.x. Sin embargo, el nuevo prefijo UNSAFE_ ayudará a resaltar los componentes con patrones problemáticos durante las revisiones de código y sesiones de depuración. (Si quisieras, podrías desalentar aún más su uso en tu aplicación con el Modo Estricto opcional.)

Nota

Aprende más acerca de nuestra política de versionamiento y compromiso con la estabilidad.

Deprecación de URLs javascript:

Los URLs que inician con javascript: son una superficie de ataque peligrosa, porque es fácil incluir de forma accidental salida no sanitizada en una etiqueta como <a href> y crear una falla de seguridad:

const userProfile = {
  website: "javascript: alert('you got hacked')",
};
// Esto emitirá un advertencia:
<a href={userProfile.website}>Profile</a>

En React 16.9, este patrón continua funcionando, pero emitirá una advertencia en la bitácora. Si usas URLs javascript: para lógica, intenta usar los manejadores de eventos de React en su lugar. (Como último recurso, puedes eludir la protección con dangerouslySetInnerHTML, pero esto es ampliamente desaconsejado y a menudo conduce a fallas de seguridad.)

En una futura versión mayor, React emitirá un error si encuentra un URLjavascript:.

Deprecación de componentes “Factory”

Antes de que compilar clases Javascript con Babel se hiciera popular, React tenía soporte para un componente “factory” que retornaba un objeto con un método render:

function FactoryComponent() {
  return { render() { return <div />; } }
}

Este patrón es confuso porque se parece mucho a un componente funcional - pero no lo es. (Un componente funcional tan solo retornaría el <div /> en el ejemplo de arriba.)

Este patrón casi nunca es usado, y soportarlo hace que React sea ligeramente más grande y lento de lo necesario. Así que estamos deprecando este patrón en 16.9 y registrando una advertencia en la bitácora si es encontrado. Si dependes de él, añadir FactoryComponent.prototype = React.Component.prototype puede servir como una solución. Otra alternativa sería convertirlo a una clase o a un componente funcional.

No esperamos que la mayoría de las bases de código sean afectadas por esto.

Nuevas funcionalidades

act() Asíncrono para Pruebas

React 16.8 introdujo una nueva utilidad de pruebas llamada act() para ayudar a escribir pruebas que representaran mejor el comportamiento de los navegadores. Por ejemplo, múltiples actualizaciones de estado en un sólo act() son agrupadas. Esto coincide con como React funciona al manejar eventos reales en el navegador, y ayuda a preparar tus componentes para un futuro en el que React agrupará las actualizaciones más a menudo.

Sin embargo, en 16.8 act() solo soportaba funciones síncronas. A veces, podrías haber visto una advertencia como esta en una prueba pero no podías arreglarla fácilmente:

An update to SomeComponent inside a test was not wrapped in act(...).

En React 16.9, act() también acepta funciones asíncronas, y puedes usar await al invocarlo:

await act(async () => {
  // ...
});

Esto soluciona los casos restantes en los que antes no podías usar act(), tales como cuando la actualización del estado se realizaba dentro de una función asíncrona. Como resultado, ahora deberías ser capaz de arreglar el resto de las advertencias de act() en tus pruebas.

Hemos escuchado que no había suficiente información acerca de como escribir pruebas con act(). La nueva guía de Recetas de Pruebas describe escenarios comunes, y cómo act() puede ayudarte a escribir buenas pruebas. Estos ejemplos usan los APIs vainilla del DOM, pero también puedes usar React Testing Library para reducir el código repetitivo. Muchos de sus métodos ya usan act() internamente.

Por favor haznos saber en el registro de incidentes si consigues algún escenario donde act() no funcione bien para tí, e intentaremos ayudar.

Medidas de Desempeño con <React.Profiler>

En React 16.5, introdujimos un nuevo Perfilador de React para DevTools que ayuda a encontrar los cuellos de botella de desempeño en tu aplicación. En React 16.9, también estamos añadiendo una forma programática de recopilar medidas llamada <React.Profiler>. Esperamos que la mayoría de las aplicaciones más pequeñas no la usen, pero puede ser útil hacer un seguimiento a las regresiones de desempeño a lo largo del tiempo en aplicaciones más grandes.

El <Profiler> mide cuan a menudo una aplicación React renderiza y cual es el “costo” de renderizar. Su propósito es ayudar a identificar las partes de una aplicación que son lentas y pudieran beneficiarse de optimizaciones tales como la memoización.

Un <Profiler> puede ser añadido en cualquier parte del árbol de React para medir el costo de renderizar esa parte. Require dos props: un id (cadena de caracteres) y un callback onRender (función) la cual React llama cada vez que un componente dentro del árbol haga “commit” de una actualización.

render(
  <Profiler id="application" onRender={onRenderCallback}>
    <App>
      <Navigation {...props} />
      <Main {...props} />
    </App>
  </Profiler>
);

Para aprender más acerca de el Profiler y los parámetros pasados al callback onRender, revise la documentación del Profiler.

Nota:

Realizar perfilamiento añade una carga adicional, así que está desahabilitado en la compilación de producción.

Para elegir usar perfilamiento en producción, React proveé una compilación especial de producción con el perfilamiento habilitado. Lea más acerca de como usar esta compilación en fb.me/react-profiling.

Correcciones de Errores Notables

Esta versión contiene algunas otras mejoras notables:

  • Un crash al llamar findDOMNode() dentro de un árbol <Suspense> ha sido corregido.

  • Una fuga de memoria causada por la retención de sub-árboles eliminados también ha sido corregida.

  • Un bucle infinto causado por setState en useEffect ahora registra un error en la bitácora. (Esto es similar al error que se observa cuando se llama setState en componentDidUpdate en una clase.)

Estamos agradecidos con todos quienes contribuyeron a identificar y a arreglar estos y otros errores. Puedes encontrar la bitácora completa de cambios abajo.

Una Actualización a la Hoja de Ruta

En Noviembre de 2018, habías publicado la siguiente hoja de ruta para las versiones 16.x:

  • Una versión menor 16.x con React Hooks (estimado anterior: 1er Trimestre 2019)
  • Una versión menor 16.x con Modo Concurrente (estimado anterior: 2do Trimestre 2019)
  • Una versión menor 16.x con Suspense para Obtención de Datos (estimado anterior: Mediados 2019 )

Estos estimados eran muy optimistas, y hemos necesitado ajustarlos.

tldr: Liberamos Hooks a tiempo, pero estamos reagrupando Modo Concurrente y Suspense para Obtención de Datos en una sola versión que tenemos la intención de liberar después en este año.

En Febrero, liberamos una versión 16.8 estable incluyendo React Hooks, con soporte para React Native un més después. Sin embargo, subestimamos el trabajo de seguimiento para esta versión, incluyendo las reglas de validación, herramientas de desarrollo, ejemplos, y más documentación. Esto retrasó nuestra línea de tiempo unos meses.

Ahora que los Hooks de React están desplegados, el trabajo en el Modo Concurrente y Suspense para obtención de datos está en pleno apogeo. El nuevo sitio web de Facebook que está actualmente en desarrollo activo está construido sobre estas funcionalidades. Probarlas con código real nos ayudó a descubrir y manejar muchos errores antes de que pudieran afectar a los usuarios open source. Algunos de estos arreglos involucraron un rediseño interno de estas funcionalidades, lo cual también causó retrasos en nuestra línea de tiempo.

Con este nuevo entendimiento, aquí está lo que planeamos hacer.

Una versión en lugar de dos

El Modo Concurrente y Suspense son el poder detras del nuevo sitio web de Facebook que se encuentra en desarrollo activo, así que confiamos que están cercanos a un estado tecnicamente estable. Ahora también entendemos mejor los pasos concretos necesarios antes de que esté listo para su adopción open source.

Originalmente pensamos que dividiriamos el Modo Concurrente y Suspense para Obtención de Datos en dos versiones. Hemos encontrado que esta secuencia es confusa de explicar, porque estas funcionalides están más relacionadas de lo que creiamos al principio. Así que planeamos liberar el soporte a ambos Modo Concurrente y Suspense para Obtención de Datos en una sola versión combinada.

No queremos sobreprometer de nuevo la fecha de liberación. Dado que dependemos de ambos en código en producción, esperamos proveer una versión 16.x con soporte opcional para ambos este año.

Una actualización sobre la Obtención de Datos

Aunque React no es opinionado acerca de como obtienes datos, la primera versión de Suspense para Obtención de Datos probablemente estará enfocada en integrarse con librerías de obtención de datos opinionadas. Por ejemplo, en Facebook estamos usando las próximas APIs de Relay que se integran con Suspense. Nosotros documentaremos cómo otras librerías opinionadas como Apollo pueden soportar una integración similar.

En la primera versión, no tenemos la intención de enfocarnos en la solución ad-hoc “dispara una solicitud HTTP” que usamos en los demos iniciales (también conocido como “React Cache”). Sin embargo, esperamos que tanto nosotros como la comunidad React estaremos explorando este espacio en los próximos meses luego de la versión inicial.

Una Actualización sobre Renderizado en Servidor

Hemos iniciado el trabajo en el nuevo renderizador en servidor con capacidad de Suspense, pero no esperamos que esté listo para la versión inicial de Modo Concurrente. Esta versión, sin embargo, proveerá una solución temporal que permita al renderizador en servidor actual emitir HTML para planes alternativos de Suspense de forma inmediata, y renderizar su contenido real en el cliente. Esta es la solución que estamos usando actualmente nosotros en Facebook, hasta que el renderizador en streaming esté listo.

¿Porqué está tomando tanto tiempo?

Hemos liberado las piezas individuales que llevan al Modo Concurrente a medida que se han estabilizado, incluyendo la nueva API de contexto, carga diferida con Suspense, y Hooks. Nosotros también estamos ansiosos de liberar las otras partes faltantes, pero probarlas a escala es una parte importante del proceso. La respuesta honesta es que tomó más trabajo del que esparabamos cuando iniciamos. Como siempre, apreciamos sus preguntas y feedback en Twitter y en nuestro registro de incidencias.

Instalación

React

React v16.9.0 está disponible en el registro npm.

Para instalar React 16 con Yarn, ejecute:

yarn add react@^16.9.0 react-dom@^16.9.0

Para instalar React 16 con npm, ejecute:

npm install --save react@^16.9.0 react-dom@^16.9.0

También proveemos compilaciones UMD de React por medio de una CDN:

<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

Refierase a la documentación para instrucciones detalladas de instalación.

Bitácora de Cambios

React

  • Se añadió el API <React.Profiler> para recopilar medidas de desempeño programáticamente. (@bvaughn en #15172)
  • Eliminar unstable_ConcurrentMode a favor de unstable_createRoot. (@acdlite en #15532)

React DOM

  • Deprecar los nombres viejos para los métodos de ciclo de vida UNSAFE_*. (@bvaughn en #15186 y @threepointone en #16103)
  • Deprecar URLs javascript: como una superficie de ataque común. (@sebmarkbage en #15047)
  • Deprecar los poco comunes componentes “patrón módulo” (factory). (@sebmarkbage en #15145)
  • Añadir soporte al atributo disablePictureInPicture en <video>. (@eek en #15334)
  • Añadir soporte para el evento onLoad para <embed>. (@cherniavskii en #15614)
  • Añadir soporte para editar el estado de useState desde DevTools. (@bvaughn en #14906)
  • Añadir soporte para habilitar Suspense desde DevTools. (@gaearon en #15232)
  • Advertir cuando setState es llamado desde useEffect, creando un bucle. (@gaearon en #15180)
  • Arreglar una fuga de memoria. (@paulshen en #16115)
  • Arreglar un crash dentro de findDOMNode para componentes envueltos en <Suspense>. (@acdlite en #15312)
  • Arreglar que los efectos pendientes sean aplicados demasiado tarde. (@acdlite en #15650)
  • Arreglar el orden incorrecto de los argumentos en un mensaje de advertencia. (@brickspert en #15345)
  • Arreglar ocultar los nodos de falla de Suspense cuando hay un estilo !important. (@acdlite en #15861 and #15882)
  • Mejorar ligeramente el desempeño de la hidratación. (@bmeurer en #15998)

Servidor React DOM

  • Arreglar salida incorrecta para nombres de propiedades CSS custom en camelCase. (@bedakb en #16167)

Utilidades de prueba de React y Renderizador de Prueba