Guía para comenzar con Next.js - Crear una aplicación Next.js

En esta guía, aprenda todo lo que necesita saber sobre Next.js, una extensión de React.js con Node.js. Experimente las páginas de Next.js, el enrutamiento del sistema de archivos, SSR, SG, renderizado previo y más a través de una aplicación funcional.

Introducción

Next.js es un marco JavaScript de código abierto creado por Vercel para mejorar las aplicaciones de React con funciones como Representación del lado del servidor y Generación de sitios estáticos.

Tradicionalmente, React se usa para crear Aplicaciones de una sola página (SPA) cuyo contenido se representa en el lado del cliente. Next.js amplía esto al permitir que los desarrolladores creen aplicaciones que pueden realizar acciones del lado del servidor, rutas de búsqueda previa y soporte para TypeScript. Además de eso, ¡no requiere ninguna configuración adicional por defecto!

En esta guía, veremos las funciones y el funcionamiento pertinentes de Next.js. Para solidificar el nuevo conocimiento, crearemos una aplicación meteorológica completa de varias páginas, que se comunica con API externas y permite que un usuario registre determinados estados.

{.icon aria-hidden=“true”}

Nota: El código completo de esta aplicación se puede encontrar en GitHub.

Instalación y configuración

La forma más fácil de crear una nueva aplicación Next.js es mediante la herramienta CLI create-next-app. Puede instalarlo a través de npm:

1
$ npm install create-next-app

Una vez instalada, puede inicializar una nueva aplicación Next.js llamando a la herramienta y proporcionando un nombre para su proyecto:

1
$ npx create-next-app weather-app

{.icon aria-hidden=“true”}

Nota: Si aún no tiene create-next-app instalado, npx le pedirá que lo instale automáticamente.

Una vez que la herramienta terminó de inicializar un proyecto esqueleto, pasemos al directorio y echemos un vistazo dentro:

1
2
3
4
$ cd weather-app
$ ls
README.md       node_modules/      package.json  public/
next.config.js  package-lock.json  pages/        styles/

El estándar package.json, package-lock.json y node_modules están ahí, sin embargo, también tenemos los directorios /pages, /public y /styles, así como un archivo next.config.js!

Echemos un vistazo a lo que estos son.

Funciones de Next.js

Next.js es, en última instancia, una extensión para React, e introduce un par de cosas nuevas que hacen que el desarrollo de aplicaciones React sea más simple y rápido, comenzando con las páginas Next.js.

Páginas

Next.js hace que la creación de aplicaciones de varias páginas con React sea ridículamente fácil con su enrutador basado en el sistema de archivos predeterminado. No necesita instalar ningún paquete adicional, como react-router-dom, o configurar un enrutador.

Todos los proyectos de Next.js incluyen un directorio /pages predeterminado, que es el hogar de todos los componentes de React que utilizará. Para cada componente, un enrutador servirá una página basada en ese componente.

Un componente de React es una página a los ojos de Next, y se sirve automáticamente en la ruta correspondiente a su nombre de archivo.

Por ejemplo, supongamos que creamos un componente, contact.js, dentro del directorio /pages:

1
2
3
4
5
6
7
8
9
const Contact = () => {
    return (
        <div>
            Contact
        </div>
    )
}

export default Contact

¡El enrutador basado en el sistema de archivos que emplea Next.js hará que esta página sea accesible bajo la ruta / contacto! La única excepción a esta regla es la página index.js, que no se encuentra en la ruta /index, sino que se sirve en /.

Además, puede anidar rutas con Next.js, por lo que puede crear fácilmente un /weather/berlin dinámicamente creando la carpeta /weather y un componente dinámico [city].js para que actúe como la página .

{.icon aria-hidden=“true”}

Nota: Para las rutas dinámicas, debe nombrar el archivo entre corchetes. Sin ellos, es una cadena literal estática y se analizará como tal. city.js se resolvería en la ruta /weather/city, y no coincidiría con nada más. Por otro lado, [city.js] coincidiría con /weather/berlin, /weather/london, /weather/lagos, etc.

El componente <Enlace>

El componente <Link> se puede usar para navegar entre las páginas de sus aplicaciones. Suponiendo que la estructura de la página de nuestro proyecto tiene varias páginas en el directorio /pages:

1
2
3
4
- pages
  - index.js
  - weather.js
  - contact.js

El atributo href del componente <Link> se puede usar para señalar la ruta relativa de cada página, comenzando en el directorio /pages:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import Link from "next/link";

export default function Home() {
  return (
    <div>
      <Link href="/">Home</Link>
      <Link href="/weather">Weather</Link>
      <Link href="/contact">Contact</Link>
    </div>
  )
}

Naturalmente, si tiene una jerarquía anidada de archivos, también puede vincular a páginas anidadas:

1
2
3
- pages
  - weather
    - [city].js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import Link from "next/link";

export default function Weather() {
  return (
    <div>
      <Link href="/weather/berlin">Berlin</Link>
      <Link href="/weather/london">London</Link>
      <Link href="/weather/lagos">Lagos</Link>
    </div>
  )
}

¡El componente <Link> también puede buscar previamente páginas! Una vez que se ha cargado una página y hay varios enlaces a otras páginas, si sabe que una determinada página se visitará con frecuencia o desea asegurarse de que la página se cargue lo antes posible (sin afectar la página inicial). ), puede obtener previamente la página asociada con un <Enlace> para que la transición sea más rápida y fluida.

De hecho, Next.js precarga todas las páginas por defecto. Con ese fin, si desea acelerar la transición a una página determinada, establezca el atributo prefetch en falso para otras páginas.

Por ejemplo, es concebible que en una aplicación meteorológica, es más probable que las personas naveguen a la ruta /weather desde la página de inicio, en lugar de /about. No hay necesidad de obtener previamente la página/componente about.js, ya que estaría cargando más al servidor para una página en la que no es muy probable que se haga clic. Por otro lado, lo más probable es que weather.js sea la próxima ruta que visiten las personas, por lo que puede ahorrar algo de tiempo en la transición al obtenerlo previamente:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import Link from "next/link";

export default function Home() {
  return (
    <div>
      <Link prefetch=true href="/weather">Weather</Link>
      <Link prefetch=false href="/about">About Us</Link>
    </div>
  )
}

Algunos otros atributos incluyen el atributo scroll (que por defecto es true), que lleva al usuario a la parte superior de la página cuando se redirige a sí mismo con un <Enlace>. Este es un valor predeterminado muy sensato, aunque es posible que desee desactivarlo para obtener un efecto más específico que le gustaría lograr.

Otro atributo que vale la pena mencionar es el atributo reemplazar, que por defecto es falso. Si se establece en true, reemplazará la última entrada en la pila del historial, en lugar de enviar una nueva, cuando navegue a una nueva página/ruta con un <Enlace>.

Páginas de representación previa

Hablando de páginas de búsqueda previa y presentación previa, esta función de Next.js es una de las más pertinentes. Nuevamente, de manera predeterminada, Next.js buscará previamente todas las páginas a las que se vincule, lo que permitirá transiciones suaves y rápidas entre ellas.

Para cada página, puede elegir entre Representación del lado del servidor o Generación estática y la técnica utilizada depende de las funciones que utilice para obtener datos. ¡No está obligado a adherirse a una de estas técnicas durante toda la aplicación!

Elegir entre SSR y SG es una cuestión de dónde le gustaría colocar la carga, y ambas técnicas procesan previamente las páginas, solo que de una manera diferente.

Si procesa sus páginas en el extremo del servidor, se procesarán en cada solicitud, utilizando los recursos de su servidor y se enviarán al usuario final. Si genera estáticamente una página, se genera una vez y es reutilizable después del tiempo de compilación.

{.icon aria-hidden=“true”}

Nota: En términos generales, querrá usar Generación estática siempre que no haya necesidad de usar Representación del lado del servidor ya que la página se puede almacenar en caché y reutilizado, ahorrando valiosos cálculos. Cada vez que los componentes de las páginas son frecuentes, se requiere Representación del lado del servidor y la página se procesa cuando se solicita con nuevos datos (algunos de los cuales pueden depender de la solicitud en sí).

También puede decidir permitir que algunas páginas o elementos de la página se representen a través de Representación del lado del cliente, que coloca la carga en la máquina del usuario final, pero no tiene garantías ni control sobre su recursos, por lo que normalmente desea evitar cualquier cálculo intensivo de su parte.

¿Qué implica el renderizado previo en la práctica?

¿Cómo afecta esto al usuario final y cómo mejora una aplicación React simple? La representación previa permite que un usuario vea la página antes de que se cargue el código JavaScript. JavaScript tarda muy poco en cargarse, pero estos milisegundos afectan inadvertidamente nuestra percepción. Aunque la página se muestra como la verá el usuario una vez que todos los componentes estén cargados, ninguno de ellos funciona todavía.

Solo una vez que se muestra la página, los componentes se procesan y cargan para convertirse en componentes interactivos. Este proceso se llama hidratación.

Pre-rendering with Next.js

Sin Next.js, la página estaría vacía mientras se carga JavaScript y se inicializan los componentes.

Rendering with React.js

{.icon aria-hidden=“true”}

Dado que la representación previa es una parte integral de Next.js, veremos algunas de las funciones que puede usar para facilitar la representación previa, tanto a través de SSR como de SG.

Obtención de datos del lado del servidor - getServerSideProps() {#obtención de datos del lado del servidor}

La función getServerSideProps() se usa para realizar operaciones relacionadas con el servidor, como obtener datos de una API externa. Nuevamente, desea realizar SSR siempre que los datos en la página cambien rápidamente, y no tendría sentido almacenarlos en caché. Por ejemplo, una API puede responder con precios de acciones actualizados, o la hora en un reloj cada segundo, y en cada solicitud del usuario; estos deben estar actualizados.

Aquí hay un ejemplo que envía una solicitud a una API de muestra y pasa los datos recibidos como apoyo a nuestro componente de página:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
const Weather = ({temperature}) => {
// display temperature

}
export default Weather

export async function getServerSideProps() {
  const res = fetch('http://example.com/api')
  ...
  const temperature = res.temperature
  return {
    props: {temperature},
  }
}

getServerSideProps() recibe un objeto de contexto, que contiene información relacionada con el servidor, como solicitudes entrantes, respuestas del servidor, consultas. Esto es crucial, porque la representación misma puede depender del contexto.

Rutas de generación estática - getStaticPaths()

Usamos la función getStaticPaths() para definir la lista de rutas que deben generarse estáticamente para una ruta dinámica. Digamos que tenemos una ruta dinámica pages/weather/[city].js y exportamos una función getStaticPaths() en este archivo como se muestra a continuación:

1
2
3
4
5
export async function getStaticPaths() {
  return {
    paths: [{ params: { id: 'paris' } }, { params: { id: 'london' } }],
  };
}

Next.js generará automáticamente de forma estática /weather/paris y /weather/london para nosotros en el momento de la compilación.

Props de generación estática - getStaticProps()

La función getStaticProps() es similar a getServerSideProps() en el sentido de que la usamos para cargar accesorios en una página renderizada previamente. En este caso, sin embargo, los accesorios se generan estáticamente en el momento de la compilación y se reutilizan para todas las solicitudes posteriores, en lugar de renderizarse en el momento de la solicitud:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
export async function getStaticProps() {

  const res = await fetch('http://someapi/toget/cities')
  ...
  const cities = await res.json()
  return {
    props: {
      cities,
    },
  }
}

{.icon aria-hidden=“true”}

Nota: getStaticPaths() no funcionará con getServerSideProps(); en su lugar, utilice getStaticProps(). Es mejor utilizar esta función solo cuando los datos que se van a renderizar previamente se cargan rápidamente o se pueden almacenar en caché públicamente.

<Head/> & SEO

Dado que las aplicaciones de una sola página son difíciles de rastrear por los motores de búsqueda, puede resultar complicado optimizar las aplicaciones de React para los motores de búsqueda. Si bien la representación del lado del servidor de Next.js soluciona esto, el marco también incluye un componente especial <Head /> que simplifica la adición de elementos al encabezado de su página.

Como resultado, es más fácil actualizar la configuración de SEO de las páginas de tu aplicación, como la etiqueta del título, la metadescripción y cualquier otro elemento que incluyas en una etiqueta estándar HTML <head>:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import Head from "next/head";

const Contact = () => {
  return (
    <div>
      <Head>
        <title>Contact</title>
        <meta name="description" content="Welcome to our contact page!"/>
      </Head>
    </div>
  );
};

export default Contact;

Creación de rutas API con Next.js

Next.js también ofrece una función para desarrollar su propia API directamente dentro de su proyecto, ¡y el proceso es similar al de la creación de páginas! Para comenzar, deberá crear un nuevo subdirectorio api en /pages (es decir, /pages/api), y cualquier archivo en este directorio se enrutará a /api/*.

Digamos, creamos un archivo /pages/api/weather.js. Se puede acceder inmediatamente a un punto final como /api/weather.

Para que estos puntos finales funcionen, debe exportar una función handler() predeterminada (manejador de solicitudes) para cada punto final, que recibe dos parámetros: req (solicitud entrante) y res (respuesta del servidor).

Para probar esto, actualicemos nuestro ejemplo /pages/api/weather.js con el siguiente contenido:

1
2
3
4
5
6
7
8
export default function handler(req, res) {
  res.status(200)
  res.json({
    city: 'London',
    temperature: '20',
    description: 'sunny',
  });
}

Si visitamos o enviamos una solicitud a /api/weather, deberíamos ver la información meteorológica ficticia de Londres devuelta, así como un código de respuesta 200.

Activos estáticos

En algún momento, probablemente querrá cargar activos como imágenes, videos, fuentes, etc. Todos los proyectos de Next.js tienen un directorio llamado /public para este propósito.

Se puede acceder a los archivos en el directorio /public desde cualquier parte de su aplicación anteponiendo la fuente con la URL base (/).

Por ejemplo, si tenemos un archivo en /public/weather-icon.svg, podemos acceder a él en cualquier componente con:

1
2
3
4
5
const WeatherIcon = () => {
  return <img src="/weather-icon.svg" alt="Weather Icon"/>
}

export default WeatherIcon

Variables de entorno Next.js

Las variables de entorno son variables cuyos valores se establecen fuera de nuestra aplicación, y las usamos principalmente para mantener datos confidenciales como claves API o configuraciones del servidor para evitar enviarlos a herramientas de control de versiones como Github, GitLab, etc.

Next.js brinda soporte para trabajar con variables de entorno, a través de un archivo .env.local. Todas las variables en este archivo están asignadas a process.env.

Si tenemos un archivo .env.local con las siguientes variables:

1
2
WEATHER_API_KEY=abcd123
CITY_API_KEY=123abc

Ahora podemos acceder a ellos a través de process.env.WEATHER_API_KEY y process.env.CITY_API_KEY.

Además, las variables de entorno no se exponen en el navegador de forma predeterminada y solo se puede acceder a ellas en el entorno de Node.js (en el lado del servidor). Sin embargo, podemos optar por exponerlos al lado del cliente anteponiendo la variable preferida con NEXT_PUBLIC_. Por ejemplo, si tenemos una variable:

1
NEXT_PUBLIC_CITY_API_KEY=123abc

Ahora se puede acceder a esta variable desde cualquier lugar de nuestra aplicación a través de process.env.NEXT_PUBLIC_CITY_API_KEY.

Creación de una aplicación meteorológica con Next.js

¡Ya hemos cubierto mucho terreno! La consolidación de nuevos conocimientos se logra mejor a través de la práctica, por lo que es útil crear una aplicación para complementar la nueva teoría.

Construiremos una aplicación meteorológica que detecte la ciudad del usuario y muestre información meteorológica basada en esa información. Además, implementaremos una función que permite a los usuarios guardar información meteorológica específica en cualquier momento y acceder a ella más tarde.

La aplicación se verá algo como esto:

creating a weather app with next.js

Si aún no lo ha hecho, cree una nueva aplicación Next.js con el siguiente comando:

1
$ npx create-next-app weather-app

Y podemos iniciar nuestra aplicación con:

1
$ npm run dev

En aras de la simplicidad y la brevedad, usaremos Bootstrap para configurar la interfaz de nuestra aplicación en lugar de escribir CSS personalizado. Puede instalar Bootstrap usando el siguiente comando:

1
$ npm install bootstrap

Una vez que se complete la instalación, abramos pages/_app.js e incluyamos una entrada para Bootstrap:

1
2
3
4
5
6
7
8
import "bootstrap/dist/css/bootstrap.css";
import "../styles/globals.css";

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />;
}

export default MyApp;

{.icon aria-hidden=“true”}

Nota: El archivo _app.js es el componente App predeterminado que utiliza Next.js para inicializar las páginas. Sirve como punto de partida para todos los componentes de su página.

Ahora, podemos hacer que nuestra aplicación sea más atractiva visualmente cambiando la fuente predeterminada y agregando un bonito color de fondo. Abramos styles/global.css y hagamos los siguientes cambios:

1
2
3
4
5
6
7
@import url('https://fonts.googleapis.com/css2?family=Be+Vietnam+Pro:[correo electrónico protegido];200;300;400;500;800;900&display=swap');

body {
  background: #4F32FF;
  color: #fff;
  font-family: 'Be Vietnam Pro', sans-serif;
}

¡Eso es más que suficiente para ponerse en marcha! Definamos la estructura de nuestras páginas y marcadores de posición para los datos cuando se obtienen a través de una API.

Marcado de página

Para nuestro front-end, abramos pages/index.js y definamos el marcado (estructura) de nuestra página de inicio:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import Link from "next/link";

export default function Home() {
  return (
    <div>
      <div
        className="d-flex justify-content-center align-items-center"
        style={{ minHeight: "100vh" }}
      >
        <div>
          <div>
            <h1 className="fw-bolder" style={{ fontSize: "60px" }}>
              Null City.
            </h1>
            13 January, 2022
          </div>
          <div className="d-flex justify-content-between align-items-center mt-4">
            <div className="pe-5">
              <h2 className="d-inline">0</h2>
              <sup>°C</sup>
              <p className="text-info">Cloudy</p>
            </div>
            <div>
              <img src="/1.png" alt="" width={100} draggable="false" />
            </div>
          </div>
          <hr />
          <div className="d-md-flex justify-content-between align-items-center mt-4">
            <button className="btn btn-success border-0 save-btn px-4 py-3">
             Timestamp
            </button>
            <Link href="/history">
              <button className="btn btn-danger border-0 history-btn px-4 py-3 ms-auto">
                My History
              </button>
            </Link>
          </div>
        </div>
      </div>
    </div>
  );
}

{.icon aria-hidden=“true”}

Nota: Deberás descargar el ícono del clima de nuestro GitHub e incluirlo en la carpeta /public de su proyecto.

Y, en este punto, si previsualizamos nuestra aplicación en el navegador, deberíamos ver el siguiente resultado con datos ficticios:

dummy data preview

Obtener información meteorológica

Utilizaremos una API meteorológica gratuita para obtener la información meteorológica actual del usuario, pero como queremos mostrar la información meteorológica de la ciudad en la que se encuentra el usuario, necesitaremos utilizar otra API para obtener la información meteorológica del usuario. de la ciudad actual y pase este parámetro a la API meteorológica para obtener la información deseada.

La siguiente imagen describe este proceso.

orden de operación de la aplicación

Para obtener la información meteorológica, utilizaremos la API de OpenWeather, y si bien brindan un plan gratuito, deberá crear una cuenta para poder adquirir una clave API.

Y para recuperar la ciudad del usuario, estaremos haciendo uso de una [API de geolocalización de IP] gratuita (https://ip-api.com/) que no requiere una clave API para usar.

Además, queremos asegurarnos de mostrar la información meteorológica inmediatamente después de cargar la página, por lo que Next.js getServerSideProps() es útil aquí.

Ahora, agreguemos las siguientes exportaciones a index.js para realizar todas las funciones mencionadas anteriormente:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
export async function getServerSideProps() {
  const ipRequest = await fetch(`http://ip-api.com/json/`);
  const ipData = await ipRequest.json();
  const city = ipData.regionName;

  const api_key = 'YOUR_OPEN-WEATHER_API_KEY';
  const url = `http://api.openweathermap.org/data/2.5/weather?q=${city},&appid=${api_key}&units=metric`;
  const weatherRequest = await fetch(url);
  const weatherInfo = await weatherRequest.json();

  console.log(weatherInfo);
  return { props: { weatherInfo, city } };
}

El código anterior realiza dos operaciones asincrónicas:

  • La primera es recuperar la ciudad del usuario, la cual almacenamos en una variable llamada ciudad.
  • El segundo es enviar una solicitud a la API meteorológica.

Y, por último, hemos pasado el resultado devuelto por la API meteorológica, así como la ciudad como apoyo a nuestra página de índice.

{.icon aria-hidden=“true”}

Nota: Deberá reemplazar YOUR_OPEN-WEATHER_API_KEY con su propia clave API de OpenWeather.

La información requerida ahora se almacena como accesorio para nuestra página de índice en weatherInfo y city, y podemos acceder a ellos a través de:

1
2
3
4
...
export default function Home({ weatherInfo, city }) {
...
}

Si intenta registrar weatherInfo en la consola, notará que se devuelve una gran cantidad de información, incluida la coordenada del usuario y alguna otra información que no es necesaria para nuestra aplicación. Según el diseño de nuestra aplicación, solo necesitaremos los siguientes datos:

  • Ciudad del usuario
  • Temperatura actual
  • Descripción del clima (por ejemplo, nublado, lluvia ligera, nieve, etc.)

Finalmente, un ícono del clima basado en la temperatura actual. La temperatura actual se devuelve en weatherInfo.main.temp y la descripción del tiempo en weatherInfo.weather[0].description.

Entonces, sigamos adelante y reemplacemos los datos ficticios en nuestro marcado con esta información:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
{/* ... */}
<div>
  <h1 className="fw-bolder" style={{fontsize: "60px"}}>
    {city}
  </h1>
  13 January, 2022
</div>
<div className="d-flex justify-content-between align-items-center mt-4">
  <div className="pe-5">
    <h2 className="d-inline">
        {Math.round(weatherInfo.main.temp)}</h2>
    <sup>°C</sup>
    <p className="text-info text-capitalize">
        {weatherInfo.weather[0].description}
    </p>
  </div>
  <div><img src='/1.png' alt="" width={100} draggable="false" /></div>
</div>
{/* ... */}

También podemos usar la API de OpenWeather para obtener un ícono del clima dependiendo de la temperatura actual simplemente pasando el nombre del ícono como parámetro y, afortunadamente, esto también está disponible en $weatherInfo.weather[0].icon.

Entonces, sigamos adelante y reemplacemos la etiqueta <img> del icono con el siguiente código:

1
2
3
4
5
{/* ... */}
<img
  src={`http://openweathermap.org/img/wn/${weatherInfo.weather[0].icon}@2x.png`}
/>
{/* ... */}

Y nuestra aplicación debería estar completamente operativa, mostrando la información meteorológica actual basada en la ciudad en la que nos encontramos actualmente:

working preview of next.js app

Guardar datos localmente {#guardar datos localmente}

Ahora, vamos a crear una función que guarde la información meteorológica actual, así como la fecha y la hora en que se almacenó en el localStorage del navegador. Cada entrada se guardará como un objeto con la siguiente estructura:

1
2
3
4
5
6
7
{
  date: 'Current Date',
  time: 'Current Time',
  city: 'User\'s City',
  temperature: 'User\'s city temperature',
  description: 'Weather Description',
};

Para hacer esto, crea una nueva función saveWeather() (todavía dentro de nuestro archivo index.js) con el siguiente código:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
  const saveWeather = () => {
    const date = new Date();

    let data = {
      date: `${date.getDate()} ${date.getMonth() + 1} ${date.getFullYear()}`,
      time: date.toLocaleTimeString(),
      city: city,
      temperature: weatherInfo.main.temp,
      description: weatherInfo.weather[0].description,
    };

    let previousData = localStorage.getItem('weatherHistory');
    previousData = JSON.parse(previousData);
    if (previousData === null) {
      previousData = [];
    }
    previousData.push(data);
    localStorage.setItem('weatherHistory', JSON.stringify(previousData));
    alert('Weather saved successfully');
  };

El código anterior analizará todos los datos previamente almacenados en localStorage.weatherHistory como JSON y, según el tipo de datos devueltos, empujamos nuestra nueva entrada a una matriz, convertimos esta matriz en una cadena y la restauramos en localStorage .weatherHistory. Necesitamos hacer esto porque localStorage solo puede almacenar cadenas y ningún otro tipo de datos.

If you'd like to read more about localStorage - read our Guía para almacenar datos en el navegador con LocalStorage!

Y, por supuesto, queremos llamar a esta función cuando el usuario haga clic en el botón Timestamp, así que agreguemos un atributo onClick al botón:

1
<button onClick={saveWeather}>Timestamp</button>

Página de historial meteorológico

Finalmente, necesitaremos crear una página dedicada para acceder a toda la información meteorológica que se guarda en el almacenamiento local de nuestro navegador.

{.icon aria-hidden=“true”}

Nota: No podremos usar las funciones de obtención de datos de Next.js porque localStorage o cualquier otro objeto de documento no está disponible en el servidor, por lo tanto, tendremos que confiar en el cliente- obtención de datos laterales.

Cree un nuevo archivo history.js en el directorio pages con el siguiente contenido:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import { useState, useEffect } from "react";

const History = ({}) => {
  const [weatherHistory, setweatherHistory] = useState([]);


  useEffect(() => {
    setweatherHistory(
      localStorage.weatherHistory !== undefined
        ? JSON.parse(localStorage.weatherHistory)
        : []
    );
  }, []);

  return (
    <div
      className="d-flex justify-content-center align-items-center p-3"
      style={{ minHeight: "100vh" }}
    >
      <div>
        {" "}
        <h2>My Weather History</h2>
        <div className="mt-5">
          {weatherHistory.length > 0 ? (
            weatherHistory.map((weather, index) => {
              return (
                <div
                  key={index}
                  className="card mb-3"
                  style={{ width: "450px" }}
                >
                  <div className="card-body text-dark">
                    <h5 className="card-title ">
                      {weather.city} - {weather.date}
                    </h5>
                    <small>{weather.time}</small>
                    <hr />
                    <p className="card-text">
                      <span className="font-weight-bold">Temperature: </span>
                      {weather.temperature}
                      <sup>°C</sup>
                    </p>
                    <p className="card-text">
                      <span className="font-weight-bold">Condition: </span>
                      {weather.description}
                    </p>
                  </div>
                </div>
              );
            })
          ) : (
            <p>Nothing to see here - yet</p>
          )}
        </div>
      </div>
    </div>
  );
};

export default History;

El código anterior verifica si localStorage.weatherHistory existe, si es así, analizamos los datos y los configuramos en una nueva variable weatherHistory. Si no es así, hemos configurado esta variable en una matriz vacía.

En nuestro marcado, verificamos si hay al menos una entrada de datos en nuestra matriz weatherHistory, y usando la función .map() de JavaScript, iteramos a través de todos los elementos en weatherHistory, mostrándolos en nuestro página web.

Avancemos y hagamos clic en el botón Marca de tiempo en la página de índice para registrar la información meteorológica actual, y cuando regrese a la página de historial, debería ver algo como esto:

history page

Conclusión

Next.js es un marco de JavaScript diseñado específicamente para mejorar y fomentar el desarrollo de aplicaciones React de alto rendimiento.

En esta guía, hemos repasado las características pertinentes de la biblioteca: cómo se crean y enrutan las páginas a través de Next.js' file-routing system, cómo funciona el componente <Link>, qué búsqueda previa y la representación previa y cómo aprovecharla para mejorar la experiencia del usuario, cómo se pueden crear fácilmente rutas API y controladores de solicitudes y cómo trabajar con variables de entorno.

Para colmo, creamos una aplicación meteorológica que se comunica con API externas para obtener datos y mostrárselos al usuario final, lo que les permite guardar cualquier marca de tiempo en su almacenamiento local.

De nuevo, el código fuente completo de la aplicación está disponible en GitHub.