El enrutador es una función esencial para desarrollar aplicaciones React, entonces, ¿cómo lo implementa React Router?
¡Leamos el código fuente de React Router hoy!
Primero, aprendamos la API History, que es la base.
¿Qué es la historia?
Es esta cosa:
Abrí una nueva pestaña y visité baidu.com, sougou.com, taobao.com.
Mantenga presionado el botón Atrás, aparecerá el historial, esto es el historial.
En ningún lugar:
historia.longitud 是 5
Haga clic en el botón Atrás dos veces o ejecute History.back() dos veces
regresará aquí:
En este momento, la longitud de la historia sigue siendo 5.
Porque aún se conserva la historia del antes y el después:
Además de cambiar entre el historial con History.back e History.forward, también puedes usar History.go
El valor del parámetro es delta:
History.go(0) es para actualizar la página actual.
History.go(1) es uno directo, equivalente a History.forward()
History.go(-1) es retroceder uno, lo que equivale a History.back()
Por supuesto, también puedes usar History.go(-2), History.go(3), etc.
Por ejemplo, cuando ejecuto History.go (-2), puedo saltar directamente de taobao.com a sogou.com.
También puedes reemplazar el historial actual con History.replaceState:
history.replaceState({
aaa:1}, '', 'https://www.baidu.com?wd=光')
El primer parámetro es el estado, el segundo parámetro es el título y el tercero es la URL a reemplazar.
Sin embargo, el segundo parámetro básicamente no es compatible, pero se puede obtener el estado.
Por ejemplo, reemplazoState con una nueva URL en la página https://www.baidu.com:
La historia no ha cambiado antes y después, solo ha cambiado la actual:
Eso es todo:
Por supuesto, también puedes usar History.pushState para agregar un nuevo historial:
history.pushState({
bbb:1}, '', 'https://www.baidu.com?wd=东');
Pero hay un fenómeno, es decir, la historia posterior desapareció:
Es decir, queda así:
¿por qué?
Porque cuando eres History.pushState, entra en conflicto con el historial posterior, es decir, bifurcaciones:
En este momento, naturalmente, solo se puede conservar una sucursal, que es la más reciente.
En este momento, la longitud de la historia es 3.
Hasta ahora, hemos utilizado las API de longitud, ir, retroceder, avanzar, pushState, replaceState y estado del historial.
También hay un History.scrollRestoration que se utiliza para preservar la posición de desplazamiento:
Hay dos valores, automático y manual, el predeterminado es automático, es decir, localizará automáticamente la última posición de desplazamiento y no funcionará si está configurado en manual.
Por ejemplo, visité Baidu en esta ubicación:
Abra una nueva página y regrese a:
Todavía está en la posición a la que se desplazó la última vez.
Esto se debe a que su historial.scrollRestoration es automático.
Configurémoslo en manual y probémoslo:
En este momento, incluso si se desplaza hacia abajo, volverá a la parte superior cuando regrese.
Además, hay un evento relacionado con la historia: popstate
Cuando navegas por el historial, se activará popstate, como History.forwad, History.back, History.go.
Pero History.pushState, History.replaceState no activará popstate.
Probemos:
history.pushState({
aaa:1}, '', 'https://www.baidu.com?#/aaa');
history.pushState({
bbb:2}, '', 'https://www.baidu.com?#/bbb');
Agregué dos historias a la página pushState de www.baidu.com.
Hay un total de 4 páginas de navegación:
Luego escucho el evento popstate:
window.addEventListener('popstate', event => {console.log(event)});
La ejecución de History.back y History.forward activará el evento popstate:
El evento contiene el estado y la URL actual también se puede obtener de target.location
Pero cuando usas History.pushState, History.replaceState no lo activa:
Es decir, agregar y modificar el historial no activará popstate, solo al navegar entre estados.
En resumen, hemos repasado la historia de los eventos api y popstate.
En base a estos, se puede implementar React Router.
Algunos estudiantes dijeron, ¿no hay un evento de cambio de hash?
De hecho, eso es para monitorear los cambios de hash.
En base a esto, también se puede implementar el enrutador, pero obviamente, hashchange solo puede monitorear los cambios de hash, y popstate no es solo cambios de hash, sino que tiene más funciones.
Entonces usar el evento popstate es suficiente.
De hecho, en el enrutador de reacción, solo se usa el evento popstate y no el evento hashchange:
A continuación, echemos un vistazo más de cerca a cómo se implementa React Router.
Crea un proyecto de reacción:
npx create-react-app react-router-test
Instale el paquete reaccionar-router:
npm install react-router-dom
Luego escriba el siguiente código en index.js:
import React from 'react';
import ReactDOM from 'react-dom/client';
import {
createBrowserRouter,
Link,
Outlet,
RouterProvider,
} from "react-router-dom";
function Aaa() {
return <div>
<p>aaa</p>
<Link to={
'/bbb/111'}>to bbb</Link>
<br/>
<Link to={
'/ccc'}>to ccc</Link>
<br/>
<Outlet/>
</div>;
}
function Bbb() {
return 'bbb';
}
function Ccc() {
return 'ccc';
}
function ErrorPage() {
return 'error';
}
const routes = [
{
path: "/",
element: <Aaa/>,
errorElement: <ErrorPage/>,
children: [
{
path: "bbb/:id",
element: <Bbb />,
},
{
path: "ccc",
element: <Ccc />,
}
],
}
];
const router = createBrowserRouter(routes);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<RouterProvider router={
router} />);
Cree un enrutador a través de createBrowserRouter del paquete react-router-dom y pase la configuración de rutas.
Luego pase el enrutador al RouterProvider.
Hay una ruta raíz /, dos rutas secundarias /bbb/:id y /ccc
Ejecute el servicio de desarrollo:
npm run start
Bajo la prueba:
Aquí se representan los componentes correspondientes a las subrutas.
Cuando no hay una ruta correspondiente, se devolverá una página de error:
Entonces, ¿cómo se hizo realidad?
Realizamos la depuración de puntos de interrupción:
Cree un archivo de configuración de depuración launch.json y luego cree una configuración de depuración de tipo chrome:
Haga un punto de interrupción en createBrowserRouter:
Haga clic en depurar:
El código se romperá aquí:
Haga clic en entrar para ingresar a la función:
Llama a createRouter:
La historia se transmite aquí.
Esta no es una API de historia nativa, sino un contenedor:
Simplemente concéntrese en los cuatro métodos de escuchar, enviar, reemplazar y listo:
escuchar es escuchar eventos popstate.
Y empujar, reemplazar y listo son encapsulaciones de la API de historial:
Además, el historial también encapsula el atributo de ubicación, por lo que no es necesario buscarlo usted mismo desde la ventana.
Luego createRouter hará una comparación entre la configuración de rutas y la ubicación actual:
matchRoutes aplanará las rutas anidadas y hará coincidir la ubicación:
Luego, el componente a renderizar y las subrutas que contiene coinciden:
De esta manera, cuando se renderiza el árbol de componentes, se sabe qué componentes renderizar:
Es para rendir el resultado del partido.
Esto completa el renderizado del componente correspondiente a la ruta:
Este es el proceso:
Al hacer clic en el enlace para cambiar de ruta:
Se ejecutará el método de navegación:
Luego vino el proceso de matchRoutes:
Después de la coincidencia, pushState o replaceState modificarán el historial y luego actualizarán el estado:
Luego se activa setState y el árbol de componentes se volverá a representar:
Este es el proceso:
router.navigate pasará a una nueva ubicación y luego comparará las rutas para encontrar una ruta coincidente.
Luego, pushState modificará el historial y activará setState de reaccionar para volver a renderizar. Al volver a renderizar, los componentes coincidentes actuales se renderizarán a través de renderMatches.
Al renderizar en Outlet, los componentes actuales que deben renderizarse se sacarán del contexto para renderizar:
Este es el proceso de renderizado cuando el enrutador renderiza por primera vez y cuando se hace clic en el enlace.
¿Qué pasa cuando se hace clic en los botones de avance y retroceso?
Esto es para escuchar popstate y luego navegar:
El proceso de seguimiento es el mismo.
Mirando hacia atrás, de hecho, las rutas del enrutador de reacción en realidad admiten estos dos métodos de configuración:
Mismo efecto.
Puedes ver por qué mirando el código fuente:
En primer lugar, el componente Ruta es un componente vacío, nada:
En el componente Rutas, los parámetros de todos los subcomponentes se eliminarán y se convertirán en configuraciones de ruta uno por uno:
¿No es el resultado el mismo que la configuración del objeto?
Resumir
Aprendimos el principio de implementación de la API histórica y React Router.
La API de historial tiene estos:
- longitud: el número de la historia
- adelante: avanzar uno
- atrás: atrás uno
- ir: adelante o atrás n
- pushState: agregar un historial
- replaceState: reemplaza el historial actual
- scrollRestoration: guarde la posición de desplazamiento, el valor es automático o manual; si es manual, debe configurar la posición de desplazamiento usted mismo
Además, existen eventos popstate que pueden monitorear la navegación de History.go, History.back e History.forward para obtener la ubicación más reciente.
Tenga en cuenta aquí que pushState y replaceState no pueden desencadenar eventos popstate. Es decir, navegar entre el historial (ir, retroceder, avanzar) puede activar el estado emergente, pero modificar el historial (empujar, reemplazar) no puede activarlo.
React Router se implementa en función de estas API históricas.
Al renderizar por primera vez, coincidirá según la ubicación y las rutas configuradas, y renderizará los componentes coincidentes.
Después de hacer clic en el enlace, la ubicación y las rutas coincidirán, y luego History.pushState modificará el historial, y luego setState de reaccionar activará la nueva representación.
Al avanzar y retroceder, es decir, cuando se ejecutan History.go, History.back e History.forward, se activará popstate, este es el mismo proceso en este momento, la ubicación y las rutas coinciden, y luego se modifica History.pushState. historial, y luego, a través de reaccionar setState, se activa una nueva representación.
Al renderizar, el componente Outlet se usará para representar subrutas y useXxx se usará para recuperar información coincidente, que se pasa a través del contexto.
Este es el principio de implementación de React Router, que es inseparable de la API histórica.