[Traducción] React 17 finalmente lanzó la versión RC, ¡el funcionario dijo que 17 es una versión de transición!

Prefacio

Vue 3.0 acaba de lanzar la versión rc hace medio mes, y React lanzó la versión rc poco después.

Sin embargo, en comparación con la gran mejora de la capacidad de Vue3 para Vue2.x, React17 no parece tener actualizaciones muy potentes para React16.x.

Incluso hay esta oración en el documento reactjs / reactjs.org en GitHub : ¡

No hay características nuevas! ¡React está un poco delgado esta vez!

Entonces, ¿qué se ha actualizado? Traduzcamos este documento y echemos un vistazo:

Traducción

Dirección del documento: https://github.com/reactjs/reactjs.org/blob/c30ff1e39b9fca747198c028a33300656a90e612/content/blog/2020-08-10-react-v17-rc.md

título Autor
React 17.0: sin nuevas funciones gaearon rachelnabors

Hoy, lanzamos la primera versión RC de React v17. Han pasado dos años y medio desde la última versión principal de React . De acuerdo con nuestros estándares, ¡el lapso de tiempo es un poco más largo! En este blog, explicaremos el impacto de esta versión principal en usted y cómo probarla.

Sin novedades

React 17 es inusual porque no agrega ninguna característica nueva para los desarrolladores, sino que se enfoca en actualizar y simplificar el propio React .

Estamos desarrollando activamente nuevas funciones en React, pero no forman parte de esta versión. React 17 es la clave de nuestra estrategia de promoción en profundidad.

La razón por la que esta versión es especial es que puede pensar en React 17 como una versión de transición , lo que hará que sea más seguro incrustar un árbol de administración de versiones de React en otro árbol de administración de versiones de React.

Actualiza gradualmente

En los últimos siete años, React ha seguido una estrategia de actualización de todo o nada . Puede continuar usando la versión anterior o actualizar toda la aplicación a la nueva versión. Pero no hay una situación intermedia.

Este método ha continuado hasta el día de hoy, pero encontramos las limitaciones de la estrategia de actualización de todo o nada . Muchos cambios de API, por ejemplo, cuando se oponen al uso de la API de contexto heredado , no se pueden realizar de forma automatizada. Es posible que la mayoría de las aplicaciones nunca las hayan usado hasta ahora, pero aún así elegimos admitirlas en React. Tenemos que elegir entre admitir API obsoletas indefinidamente o seguir usando la versión anterior de React para algunas aplicaciones. Pero estos dos esquemas no son adecuados.

Por eso, queremos brindar otra solución.

React 17 comenzó a admitir la actualización gradual de la versión React . Cuando pasa de React 15 a 16 ( o de React 16 a 17 ), generalmente actualiza toda la aplicación a la vez. Esto se aplica a la mayoría de las aplicaciones. Sin embargo, si el código base se escribió hace unos años y no se mantiene bien, actualizarlo será cada vez más difícil. Aunque se pueden usar dos versiones de React en la página, todavía habrá problemas con los eventos hasta React 17.

Usamos React 17 para resolver muchos de estos problemas. Esto significará que cuando salga React 18 o una versión futura, tendrá más opciones . La primera opción es actualizar toda la aplicación a la vez como antes. Pero también puede optar por actualizar su aplicación gradualmente. Por ejemplo, puede migrar la mayoría de sus aplicaciones a React 18, pero mantener algunos diálogos de carga retrasados ​​o subrutas en React 17.

Pero esto no significa que deba actualizarse gradualmente. Para la mayoría de las aplicaciones, actualizar todo a la vez sigue siendo la mejor solución. Cargar dos versiones de React, incluso si una de ellas se carga de forma perezosa a pedido, todavía no es lo ideal. Sin embargo, para aplicaciones grandes que no se mantienen activamente, se puede considerar esta solución, y React 17 puede garantizar que estas aplicaciones no estén desactualizadas.

Para lograr una actualización gradual, debemos realizar algunos cambios en el sistema de eventos de React. Estos cambios pueden tener un impacto en el código, razón por la cual React 17 se ha convertido en una versión principal. De hecho, no hay más de 20 componentes afectados de más de 100,000 componentes, por lo que esperamos que la mayoría de las aplicaciones se puedan actualizar a React 17 sin demasiado impacto . Si encuentra algún problema, puede contactarnos .

Ejemplo de actualización gradual

Hemos preparado un repositorio de muestra ( GitHub ) que muestra cómo retrasar la carga de la versión anterior de React cuando sea necesario. Este ejemplo utiliza la aplicación Create React para compilar, pero también debería aplicarse un enfoque similar a otras herramientas. Damos la bienvenida a los desarrolladores que utilizan otras herramientas para escribir demostraciones y enviar pr.

Nota: Hemos pospuesto otras actualizaciones hasta después de React 17. El objetivo de esta versión es lograr una actualización gradual. Si actualizar React 17 es demasiado difícil, nuestro objetivo no se logrará.

Cambiar delegado de evento

Técnicamente, siempre es posible anidar diferentes versiones de React en una aplicación. Pero debido al principio de funcionamiento del sistema de eventos React, es difícil de implementar.

En los componentes de React, el manejo de eventos generalmente se escribe en línea:

<button onClick={handleClick}>

La operación DOM equivalente a este código es la siguiente:

myButton.addEventListener('click', handleClick);

Pero para la mayoría de los eventos, React no los adjunta al nodo DOM. Por el contrario, React adjuntará directamente un controlador para cada tipo de evento en el nodo del documento, que se denomina delegación de eventos . Además de sus ventajas de rendimiento en aplicaciones de gran tamaño, también facilita la incorporación de nuevas funciones, como la reproducción de eventos .

Desde su lanzamiento, React ha automatizado la delegación de eventos. Cuando se activa un evento DOM en el documento, React descubrirá a qué componente se llama, y ​​luego los eventos React "burbujearán" en el componente. Pero, de hecho, los eventos nativos han subido al nivel de "documento" y React es un controlador de eventos instalado en el documento.

Pero aquí es donde radica la dificultad de la escalada.

Si hay varias versiones de React en la página, todas registrarán controladores de eventos en el nivel superior. Esto romperá e.stopPropagation () si se evita la propagación del evento en la estructura del árbol anidado, pero el árbol externo aún puede recibirlo. Esto hace que sea muy difícil anidar diferentes versiones de React. Esta preocupación no es infundada, por ejemplo, el editor de Atom encontró el mismo problema hace cuatro años .

Es por eso que queremos cambiar la forma en que React adjunta eventos en la parte inferior.

En React 17, React ya no agregará controladores de eventos al documento. En cambio, el controlador de eventos se adjuntará al nodo DOM raíz que representa el árbol de React:

const rootNode = document.getElementById('root');
ReactDOM.render(<App />, rootNode);

En React 16 o anterior, React ejecutará document.addEventListener () para la mayoría de los eventos. React 17 llamará a rootNode.addEventListener () en la parte inferior.

Gracias a este cambio, ahora es posible anidar versiones antiguas y nuevas de árboles React de forma más segura . Tenga en cuenta que para que funcione, ambas versiones deben ser 17 o superior, que es la razón principal por la que se recomienda encarecidamente actualizar a React 17. En cierto sentido, React 17 es una versión de transición que hace posibles actualizaciones graduales.

Este cambio también facilita que React incruste aplicaciones creadas con otras tecnologías . Por ejemplo, si el "shell" de la aplicación está escrito en jQuery, pero el código más nuevo está escrito en React, e.stopPropagation () en el código de React evitará que afecte al código de jQuery, al igual que usted. Como se esperaba. En otras palabras, si ya no le gusta React y desea reescribir su aplicación (por ejemplo, con jQuery), puede convertir React a jQuery desde afuera sin interrumpir el burbujeo de eventos.

Después de la verificación, muchos de los problemas informados en el rastreador de problemas a lo largo de los años se han resuelto con nuevas funciones. La mayoría de estos problemas están relacionados con la integración de React con código que no es de React.

Nota: Es posible que se pregunte si esto romperá los portales fuera del contenedor raíz . La respuesta es que React también escucha eventos en el contenedor de portales, por lo que esto no es un problema.

Resuelve peligros ocultos

Al igual que con otras actualizaciones importantes, es posible que sea necesario ajustar el código. En Facebook, ajustamos aproximadamente diez módulos entre miles de módulos para acomodar esta actualización.

Por ejemplo, si agrega manualmente oyentes DOM en el módulo usando document.addEventListener (...), es posible que desee poder capturar todos los eventos de React. En React 16 o anterior, incluso si llama a e.stopPropagation () en el controlador de eventos React, el oyente DOM que creó aún se activará porque el evento nativo ya está en el nivel del documento. El uso de React 17 bubbling se bloqueará ( bajo demanda ), por lo que su oyente de eventos a nivel de documento no se activará:

document.addEventListener('click', function() {
    
    
  // 如果React组件调用了e.stopPropagation()
  // 那么这个自定义监听函数不会收到click事件
});

Puede convertir la supervisión para utilizar la captura de eventos para corregir este tipo de código. Para hacer esto, puede pasar {capture: true} como el tercer parámetro de document.addEventListener:

document.addEventListener('click', function() {
    
    
  // 现在这个事件处理函数使用了事件捕获,
  // 所以它可以接收到所有的点击事件!
}, {
    
     capture: true });

Tenga en cuenta que esta estrategia es más adaptable a nivel mundial. Por ejemplo, puede corregir errores existentes en el código que ocurren cuando se llama a e.stopPropagation () fuera del controlador de eventos React. En otras palabras, el burbujeo de eventos de React 17 está más cerca del DOM normal .

Otros cambios importantes

Mantenemos los cambios importantes en React 17 al mínimo. Por ejemplo, no eliminará los métodos de tarea que estaban en desuso en versiones anteriores. Sin embargo, contiene algunos otros cambios importantes y, según la experiencia, estos cambios serán relativamente seguros. En general, debido a la existencia de estos factores, no más de 20 componentes se ven afectados entre más de 100.000 componentes.

Navegador de evaluación comparativa

Hemos realizado algunas actualizaciones menores al sistema de eventos:

  • El evento onScroll ya no se propaga para evitar confusiones .
  • Los eventos onFocus y onBlur de React se han cambiado a los eventos focusin y focusout nativos en la parte inferior. Están más cerca del comportamiento existente de React y, a veces, brindan información adicional.
  • El evento de captura (por ejemplo, onClickCapture) ahora usa el detector de captura en el navegador real.

Estos cambios acercarán a React al comportamiento del navegador y mejorarán la interoperabilidad.

Nota: Aunque el evento de enfoque se cambió a focusin desde React 17, onFocus no afectó el comportamiento de burbujeo. En React, el evento onFocus siempre está burbujeando, y continúa burbujeando en React 17, porque generalmente es un valor predeterminado más útil. Consulte este espacio aislado para conocer las diferentes comprobaciones que se pueden agregar para diferentes casos de uso específicos.

Quitar grupo de eventos

La "agrupación de eventos" se eliminó en React 17. No mejora el rendimiento de los navegadores modernos e incluso confunde a los desarrolladores experimentados:

function handleChange(e) {
    
    
  setData(data => ({
    
    
    ...data,
    // This crashes in React 16 and earlier:
    text: e.target.value
  }));
}

Esto se debe a que React reutilizó objetos de eventos para diferentes eventos en navegadores antiguos para mejorar el rendimiento y establecer todos los campos de eventos en nulos antes que ellos. En React 16 y versiones anteriores, los usuarios deben llamar a e.persist () para usar el evento correctamente, o leer los atributos requeridos correctamente.

En React 17, este código se puede ejecutar como se esperaba. Se eliminó la antigua operación de optimización del grupo de eventos, por lo que los usuarios pueden leer los campos de eventos cuando sea necesario.

Esto cambió el comportamiento, por lo que lo marcamos como una actualización importante, pero en la práctica no vimos que tuviera un impacto en Facebook (¡incluso corrigió algunos errores!). Tenga en cuenta que e.persist () todavía está disponible en el objeto de evento React, pero no tiene ningún efecto.

Cuando limpiar los efectos secundarios

Estamos alineando el tiempo de useEffect con la función de limpieza.

useEffect(() => {
    
    
  // This is the effect itself.
  return () => {
    
    
    // This is its cleanup.
  };
});

La mayoría de los efectos no necesitan retrasar la actualización de la vista, por lo que React los ejecuta de forma asincrónica inmediatamente después de que la actualización se refleja en la pantalla. (En casos excepcionales, necesita un efecto secundario para evitar que se vuelva a dibujar. Por ejemplo, si necesita obtener el tamaño y posición, utilice useLayoutEffect).

Sin embargo, la función de limpieza de efectos secundarios (si existe) se ejecuta sincrónicamente en React16. Descubrimos que esto no es ideal para aplicaciones grandes, porque la sincronización ralentizará la actualización de la vista (por ejemplo, cambiar de pestaña).

En React 17, las funciones de limpieza de efectos secundarios se ejecutan de forma asincrónica; si desea desinstalar el componente, la limpieza se ejecutará después de que se actualice la vista.

Esto refleja cómo los efectos secundarios en sí mismos operan más de cerca. En casos excepcionales, es posible que desee confiar en la ejecución sincrónica, puede usar useLayoutEffect en su lugar.

Nota: Es posible que se pregunte si esto significa que ahora no podrá corregir la advertencia sobre setState en los componentes desmontados. No se preocupe, React maneja específicamente esta situación y no emitirá una advertencia setState durante el breve intervalo entre la desinstalación y la limpieza. Por lo tanto, la solicitud o el intervalo para cancelar el código casi siempre se puede conservar.

Además, React 17 ejecutará la limpieza en el mismo orden que el efecto según su posición en el árbol. En el pasado, el orden a veces era diferente.

Peligros potenciales

Las bibliotecas reutilizables pueden requerir pruebas en profundidad de esta situación, pero solo encontramos algunos componentes que interrumpirían la ejecución debido a este problema. tal como:

useEffect(() => {
    
    
  someRef.current.someSetupMethod();
  return () => {
    
    
    someRef.current.someCleanupMethod();
  };
});

El problema es que someRef.current es mutable, por lo que cuando se ejecuta la función de limpieza, es posible que se haya establecido en nulo. La solución es almacenar el valor cambiante dentro del efecto secundario :

useEffect(() => {
    
    
  const instance = someRef.current;
  instance.someSetupMethod();
  return () => {
    
    
    instance.someCleanupMethod();
  };
});

No queremos que este problema afecte a todos. El complemento lint de eslint-plugin-react-hooks / exhaustive-deps proporcionado por nosotros (asegúrese de usarlo en el proyecto) le advertirá sobre esta situación.

Devuelve un error indefinido consistente

En React 16 y versiones anteriores, devolver undefined siempre informará un error:

function Button() {
    
    
  return; // Error: Nothing was returned from render
}

Es fácil devolver indefinido sin querer:

function Button() {
    
    
  // 这里忘记了写ruturn,所以这个组件返回了一个undefined。
  // React会报错而不会忽略它。
  <button />;
}

Anteriormente, React solo realizaba esta operación en componentes de clase y función, pero no verificaba los valores de retorno de los componentes forwardRef y memo. Esto se debe a errores de codificación.

En React 17, el comportamiento de los componentes forwardRef y memo será consistente con los componentes de la función y los componentes de la clase regulares. Se informará un error cuando se devuelva undefined

let Button = forwardRef(() => {
    
    
  // 这里忘记了写ruturn,所以这个组件返回了一个undefined。
  // React17会报错而不会忽略它。
  <button />;
});

let Button = memo(() => {
    
    
  // 这里忘记了写ruturn,所以这个组件返回了一个undefined。
  // React17会报错而不会忽略它。
  <button />;
});

Si no desea realizar ningún renderizado, devuelva null.

Pila de componentes nativos

Cuando encuentre un error en el navegador, el navegador le proporcionará información de pila con el nombre y la ubicación de la función de JavaScript. Sin embargo, la pila de JavaScript no suele ser suficiente para diagnosticar el problema, porque la jerarquía del árbol de React puede ser igualmente importante. No solo necesita saber qué botón arrojó el error, sino que también desea saber dónde está el botón en el árbol de React.

Para resolver este problema, cuando encuentre un error, a partir de React 16, se imprimirá la información de la "pila de componentes". Sin embargo, todavía no son tan buenos como la pila de JavaScript nativa. En particular, no se puede hacer clic en la consola, porque React no sabe dónde se declara la función en el código fuente. Además, son casi inútiles en la producción . A diferencia de las pilas de JavaScript comprimidas convencionales, se pueden restaurar automáticamente a la posición original de la función en forma de mapa de origen. Con la pila de componentes de React, debe elegir entre la información de la pila y el tamaño del paquete en un entorno de producción.

En React 17, se usa un mecanismo diferente para generar la pila de componentes, que los une con la pila de JavaScript nativa normal. Esto le permite obtener información de pila de componentes React completamente simbolizada en un entorno de producción.

La forma en que React logra esto es un poco poco convencional. Actualmente, el navegador no puede proporcionar un método para obtener el marco de pila de funciones (archivo de origen y ubicación). Por lo tanto, cuando React detecta un error, reconstruirá la información de la pila de su componente a través del error temporal (y captura) arrojado dentro del componente. Esto aumentará la pérdida de rendimiento en el momento del bloqueo, pero solo ocurrirá una vez por tipo de componente.

Si está interesado, puede leer más detalles en este PR , pero en la mayoría de los casos, este mecanismo no afectará su código. Desde el punto de vista del usuario, la nueva característica es que se puede hacer clic en la pila de componentes (porque se basan en el marco de pila del navegador nativo) y se puede decodificar en producción como errores regulares de JavaScript.

La parte que constituye el cambio principal es que para que esta función funcione correctamente, React volverá a ejecutar algunas de las funciones anteriores y algunas partes del constructor de la clase en la pila después de detectar el error. Dado que las funciones de representación y los constructores de clases no deberían tener efectos secundarios (lo cual también es importante para SSR), esto no causará ningún problema práctico.

Eliminar exportación privada

Finalmente, el cambio principal notable es que eliminamos algunos componentes internos de React que anteriormente estaban expuestos a otros proyectos. En particular, React Native for Web solía depender de ciertos componentes internos del sistema de eventos, pero esta dependencia es frágil y, a menudo, se rompe.

En React 17, estas exportaciones privadas se han eliminado. Hasta donde sabemos, React Native for Web es el único proyecto que los usa, y han completado la migración a otros métodos que no dependen de esas funciones de exportación privadas.

Esto significa que la versión anterior de React Native para Web no será compatible con React 17, pero la nueva versión puede usarla. De hecho, no hay mucho cambio, porque React Native for Web debe lanzar una nueva versión para adaptarse a los cambios en su React interno.

Además, eliminamos el método auxiliar de ReactTestUtils.SimulateNative. Nunca se grabaron, no hicieron lo que su nombre implica y no se ocuparon de los cambios que hicimos en el sistema de eventos. Si desea una manera fácil de activar eventos en el navegador nativo durante la prueba, utilice la biblioteca de React Testing en su lugar .

instalación

Le recomendamos que pruebe la versión React 17.0 RC lo antes posible, y puede preguntarnos si encuentra algún problema durante el proceso de migración . Tenga en cuenta que la versión candidata no es estable, por lo que no la implemente en un entorno de producción.

Para instalar la versión React 17 RC a través de npm, ejecute:

npm install [email protected] [email protected]

Para instalar la versión React 17 RC a través de hilo, ejecute:

yarn add [email protected] [email protected]

También proporcionamos una versión de construcción UMD de React RC a través de CDN:

<script crossorigin src="https://unpkg.com/[email protected]/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>

Para obtener instrucciones de instalación detalladas, consulte la documentación .

Supongo que te gusta

Origin blog.csdn.net/GetIdea/article/details/107946774
Recomendado
Clasificación