Almacenamiento en caché de datos mediante parámetros de consulta de URL en JavaScript

Cómo almacenar datos temporalmente en parámetros de consulta de URL y recuperarlos y analizarlos para usarlos en su interfaz de usuario.

Primeros pasos

Para este tutorial, vamos a utilizar el marco JavaScript de pila completa de CheatCode, Joystick. Joystick reúne un marco de interfaz de usuario de front-end con un back-end de Node.js para crear aplicaciones.

Para comenzar, querremos instalar Joystick a través de NPM. Asegúrese de estar usando Node.js 16+ antes de instalar para garantizar la compatibilidad (lea este tutorial primero si necesita aprender a instalar Node.js o ejecutar varias versiones en su computadora):

Terminal

npm i -g @joystick.js/cli

Esto instalará Joystick globalmente en su computadora. Una vez instalado, vamos a crear un nuevo proyecto:

Terminal

joystick create app

Después de unos segundos, verá un mensaje desconectado de cd en su nuevo proyecto y ejecute joystick start . Antes de ejecutar joystick start , necesitamos instalar un paquete, query-string :

Terminal

cd app && npm i query-string

Este paquete nos ayudará a analizar y establecer nuestros parámetros de consulta sobre la marcha. Después de que esté instalado, continúe e inicie el servidor:

Terminal

joystick start

Después de esto, su aplicación debería estar ejecutándose y estamos listos para comenzar.

Agregando algo de CSS global

Para contextualizar mejor nuestra demostración, agregaremos CSS a lo largo del tutorial. Para comenzar, necesitamos agregar algo de CSS global que manejará la visualización general de nuestras páginas:

/index.css

* {
  margin: 0;
  padding: 0;
}

*, *:before, *:after {
  box-sizing: border-box;
}

body {
  font-family: "Helvetica Neue", "Helvetica", "Arial", sans-serif;
  font-size: 16px;
  background: #fff;
}

.container {
  width: 100%;
  max-width: 800px;
  margin: 15px auto;
  padding: 0 15px !important;
}

@media screen and (min-width: 768px) {
  .container {
    margin-top: 50px;
  }
}

De forma predeterminada, cuando abre este archivo, solo el CSS para el body existirá la etiqueta. Los detalles aquí no importan demasiado, pero lo que estamos haciendo es agregar algunos estilos de "restablecimiento" para todos los elementos HTML en el navegador (eliminando el CSS predeterminado del navegador que agrega márgenes adicionales y relleno y cambia cómo fluyen los elementos en el cuadro modelo) y un .container clase que nos permitirá crear fácilmente un <div></div> centrado para envolver contenido.

Eso es todo lo que necesitamos aquí. Agregaremos más CSS más adelante en el nivel de componente individual. A continuación, debemos conectar una ruta para una página ficticia que usaremos para probar nuestros parámetros de consulta.

Agregar una ruta para redirigir para probar parámetros

En una aplicación Joystick, todas las rutas se definen en el servidor en un solo lugar:/index.server.js . Abramos eso ahora y agreguemos una ruta para una página ficticia a la que podamos redirigir y verifiquemos que nuestros parámetros de consulta funcionen como se esperaba:

/index.servidor.js

import node from "@joystick.js/node";
import api from "./api";

node.app({
  api,
  routes: {
    "/": (req, res) => {
      res.render("ui/pages/index/index.js", {
        layout: "ui/layouts/app/index.js",
      });
    },
    "/listings/:listingId": (req, res) => {
      res.render("ui/pages/listing/index.js");
    },
    "*": (req, res) => {
      res.render("ui/pages/error/index.js", {
        layout: "ui/layouts/app/index.js",
        props: {
          statusCode: 404,
        },
      });
    },
  },
});

Cuando ejecutaste joystick start anteriormente desde la raíz de su aplicación, este es el archivo que inició Joystick. Aquí, el node.app() La función inicia una nueva aplicación Node.js usando Express.js en segundo plano. Para Expresar, el routes objeto que se define en el objeto de opciones pasado a node.app() es entregado.

Por defecto en este objeto, vemos el / y * rutas que se están definiendo. Arriba, hemos agregado una nueva ruta /listings/:listingId . Para nuestra aplicación, estamos creando una interfaz de usuario de búsqueda de bienes raíces falsa donde los usuarios podrán personalizar algunos parámetros de búsqueda y ver listados.

Aquí, estamos creando la ruta para una página de listado falsa (no cargará ningún dato real, solo algunos datos ficticios estáticos) a la que el usuario podrá redirigir. La idea es que estableceremos algunos parámetros de consulta en la URL en el / (índice) ruta y luego permitir que el usuario haga clic en un enlace a este /listings/:listingId página. Cuando lo hagan, los parámetros de consulta que establezcamos "desaparecerán". Cuando regresen, esperamos que esos parámetros de consulta se restablezcan.

Dentro de la ruta aquí, llamamos a una función en el res objeto, res.render() que es una función especial que Joystick agrega al estándar Express res objeto. Esta función está diseñada para tomar la ruta a un componente Joystick en nuestra aplicación y representarla en la página.

Aquí, asumimos que tendremos una página ubicada en /ui/pages/listing/index.js . Vamos a conectar eso ahora.

Cableando una página de listado falsa

Este es rápido. Aquí no nos importa mucho la página en sí, solo que existe para que podamos redirigir al usuario.

/ui/pages/listing/index.js

import ui from '@joystick.js/ui';

const Listing = ui.component({
  css: `
    .listing-image img {
      max-width: 100%;
      width: 100%;
      display: block;
      height: auto;
    }

    .listing-metadata {
      margin-top: 25px;
    }

    .listing-metadata .price {
      font-size: 28px;
      color: #333;
    }

    .listing-metadata .address {
      font-size: 18px;
      color: #888;
      margin-top: 7px;
    }

    .listing-metadata .rooms {
      font-size: 16px;
      color: #888;
      margin-top: 10px;
    }
  `,
  render: () => {
    return `
      <div class="container">
        <div class="listing-image">
          <img src="/house.jpg" alt="House" />
        </div>
        <div class="listing-metadata">
          <h2 class="price">$350,000</h2>
          <p class="address">1234 Fake St. Winter, MA 12345</p>
          <p class="rooms">3br, 2ba, 2,465 sqft</p>
        </div>
      </div>
    `;
  },
});

export default Listing;

Aquí creamos un componente Joystick llamando al .component() función definida en el ui objeto que importamos del @joystick.js/ui paquete. A esa función le pasamos un objeto de opciones para definir nuestro componente.

Comenzando desde abajo, tenemos un render() función que le dice a nuestro componente el HTML que nos gustaría representar para nuestro componente. Aquí, debido a que no necesitamos una página que funcione, solo devolvemos una cadena de HTML sin formato con algunos datos codificados. Cabe destacar que el house.jpg La imagen que se representa aquí se puede descargar desde nuestro cubo S3 aquí. Esto debe colocarse en el /public carpeta en la raíz del proyecto.

Además de esto, como insinuamos anteriormente, estamos agregando algo de CSS. Para hacerlo, en un componente Joystick tenemos el css opción a la que podemos pasar una cadena de CSS. Joystick aplica automáticamente este CSS a este componente para ayudarnos a evitar filtrar los estilos a otros componentes.

Eso es todo aquí. Nuevamente, este es solo un componente ficticio para ayudarnos a probar la lógica del parámetro de consulta que configuraremos en la siguiente sección.

Conexión de una interfaz de usuario de búsqueda falsa con filtros y página de resultados

Si bien están sucediendo muchas cosas en este componente, la parte en la que queremos centrarnos es la lógica para administrar nuestros parámetros de consulta. Para llegar allí, primero, construyamos el esqueleto de la interfaz de usuario para nuestro componente y luego agreguemos la lógica real para que funcione.

Aunque no lo discutimos antes, aquí vamos a sobrescribir el contenido existente del /ui/pages/index/index.js archivo:

/ui/pages/index/index.js

import ui from '@joystick.js/ui';

const Index = ui.component({
  css: `
    .search {
      padding: 20px;
    }

    header {
      display: flex;
      margin-bottom: 40px;
      padding-left: 20px;
    }

    header > * {
      margin-right: 20px;
    }

    .options label {
      margin-right: 10px;
    }

    .options label input {
      margin-right: 3px;
    }

    .listings ul {
      display: grid;
      grid-template-columns: 1fr;
      list-style: none;
    }

    .listings ul li {
      position: relative;
      padding: 20px;
      border: 1px solid transparent;
      cursor: pointer;
    }

    .listings ul li:hover {
      border: 1px solid #eee;
      box-shadow: 0px 1px 1px 2px rgba(0, 0, 0, 0.01);
    }

    .listings ul li a {
      position: absolute;
      inset: 0;
      z-index: 5;
    }

    .listing-image img {
      max-width: 100%;
      width: 100%;
      display: block;
      height: auto;
    }

    .listing-metadata {
      margin-top: 25px;
    }

    .listing-metadata .price {
      font-size: 24px;
      color: #333;
    }

    .listing-metadata .address {
      font-size: 16px;
      color: #888;
      margin-top: 7px;
    }

    .listing-metadata .rooms {
      font-size: 14px;
      color: #888;
      margin-top: 7px;
    }

    @media screen and (min-width: 768px) {
      .search {
        padding: 40px;
      }

      .listings ul {
        display: grid;
        grid-template-columns: 1fr 1fr;
      }  
    }

    @media screen and (min-width: 1200px) {
      .listings ul {
        display: grid;
        grid-template-columns: 1fr 1fr 1fr 1fr;
      }  
    }
  `,
  render: () => {
    return `
      <div class="search">
        <header>
          <input type="text" name="search" placeholder="Search listings..." />
          <select name="category">
            <option value="house">House</option>
            <option value="apartment">Apartment</option>
            <option value="condo">Condo</option>
            <option value="land">Land</option>
          </select>        
          <select name="status">
            <option value="forSale">For Sale</option>
            <option value="forRent">For Rent</option>
            <option value="sold">Sold</option>
          </select>
          <div class="options">
            <label><input type="checkbox" name="hasGarage" /> Garage</label>
            <label><input type="checkbox" name="hasCentralAir" /> Central Air</label>
            <label><input type="checkbox" name="hasPool" /> Pool</label>
          </div>
          <a href="#" class="clear">Clear</a>
        </header>
        <div class="listings">
          <ul>
            <li>
              <a href="/listings/123"></a>
              <div class="listing-image">
                <img src="/house.jpg" alt="House" />
              </div>
              <div class="listing-metadata">
                <h2 class="price">$350,000</h2>
                <p class="address">1234 Fake St. Winter, MA 12345</p>
                <p class="rooms">3br, 2ba, 2,465 sqft</p>
              </div>
            </li>
          </ul>
        </div>
      </div>
    `;
  },
});

export default Index;

Arriba, estamos obteniendo el código HTML y CSS principal en la página para nuestra interfaz de usuario. Una vez más, nuestro objetivo es tener una interfaz de usuario de pseudo búsqueda en la que el usuario pueda establecer algunos parámetros de búsqueda y ver una lista de resultados en la página. Aquí, estamos construyendo esa interfaz de usuario central y diseñándola. Después de agregar esto, si visitamos http://localhost:2600/ (ignora el 2605 en la captura de pantalla a continuación (esto fue solo para probar mientras escribía) en nuestro navegador, deberíamos ver algo como esto:

A continuación, configuremos un estado "predeterminado" para nuestra interfaz de usuario de búsqueda (nos referimos a todo lo que se encuentra en el encabezado o la parte superior de la interfaz de usuario como "interfaz de usuario de búsqueda").

/ui/pages/index/index.js

import ui from '@joystick.js/ui';

const Index = ui.component({
  state: {
    search: '',
    category: 'house',
    status: 'forSale',
    hasGarage: false,
    hasCentralAir: false,
    hasPool: false,
  },
  css: `...`,
  render: ({ state }) => {
    return `
      <div class="search">
        <header>
          <input type="text" name="search" value="${state.search}" placeholder="Search listings..." />
          <select name="category" value="${state.category}">
            <option value="house" ${state.category === 'house' ? 'selected' : ''}>House</option>
            <option value="apartment" ${state.category === 'apartment' ? 'selected' : ''}>Apartment</option>
            <option value="condo" ${state.category === 'condo' ? 'selected' : ''}>Condo</option>
            <option value="land" ${state.category === 'land' ? 'selected' : ''}>Land</option>
          </select>        
          <select name="status" value="${state.status}">
            <option value="forSale" ${state.status === 'forSale' ? 'selected' : ''}>For Sale</option>
            <option value="forRent" ${state.status === 'forRent' ? 'selected' : ''}>For Rent</option>
            <option value="sold" ${state.status === 'sold' ? 'selected' : ''}>Sold</option>
          </select>
          <div class="options">
            <label><input type="checkbox" name="hasGarage" ${state?.hasGarage ? 'checked' : ''} /> Garage</label>
            <label><input type="checkbox" name="hasCentralAir" ${state?.hasCentralAir ? 'checked' : ''} /> Central Air</label>
            <label><input type="checkbox" name="hasPool" ${state?.hasPool ? 'checked' : ''} /> Pool</label>
          </div>
          <a href="#" class="clear">Clear</a>
        </header>
        <div class="listings">
          <ul>
            <li>
              <a href="/listings/123"></a>
              <div class="listing-image">
                <img src="/house.jpg" alt="House" />
              </div>
              <div class="listing-metadata">
                <h2 class="price">$350,000</h2>
                <p class="address">1234 Fake St. Winter, MA 12345</p>
                <p class="rooms">3br, 2ba, 2,465 sqft</p>
              </div>
            </li>
          </ul>
        </div>
      </div>
    `;
  },
});

export default Index;

En un componente Joystick, podemos pasar un state opción que se asigna a un objeto de propiedades que queremos asignar al estado interno de nuestro componente de forma predeterminada (es decir, cuando el componente se carga por primera vez). Aquí, estamos creando algunos valores predeterminados que queremos usar para nuestra interfaz de usuario de búsqueda.

La parte importante aquí, retrocede en el render() función, es que hemos agregado un argumento a nuestro render() función que anticipamos es un objeto que podemos desestructurar para "arrancar" propiedades específicas y asignarlas a variables del mismo nombre en el ámbito/contexto actual. El objeto que esperamos aquí es el component instancia (es decir, el componente que estamos creando actualmente, tal como existe en la memoria).

En esa instancia, esperamos tener acceso al state actual valor. "Estado" en este caso se refiere al estado visual de nuestra interfaz de usuario. Los valores en el state objeto están destinados a ser un medio para aumentar este estado visual sobre la marcha.

Aquí, tomamos eso state object para hacer referencia a los valores para completar nuestra interfaz de usuario de búsqueda. Tenemos tres tipos de entradas en nuestra interfaz de usuario:

  1. input que es una entrada de texto sin formato utilizada para ingresar una cadena de texto de búsqueda.
  2. select que se utiliza para las entradas de "categoría" y "estado" de nuestra lista.
  3. checkbox que se utiliza para nuestras casillas de verificación de servicios.

Abajo en nuestro HTML, estamos haciendo referencia a estos valores mediante la interpolación de cadenas de JavaScript (una función a nivel de idioma para incrustar/evaluar JavaScript dentro de una cadena). Podemos hacer esto porque el valor que devolvemos del render() de nuestro componente la función es una cadena.

Según el tipo de entrada que estemos representando, utilizamos el valor de estado correspondiente de forma ligeramente diferente. Para nuestra entrada de búsqueda de texto sin formato, podemos configurar un value atributo igual al valor de state.search .

Para nuestro selecto <select> entradas establecemos tanto un value atributo en el principal <select> etiqueta, así como un condicional selected atributo en cada opción en ese <select> lista (importante ya que si no hacemos esto, el valor actual de la entrada no aparecerá como seleccionado sin este atributo).

Finalmente, para nuestras entradas de casilla de verificación, agregamos condicionalmente un checked valor de atributo basado en el state correspondiente valor para cada entrada.

Esto nos da los fundamentos de nuestra interfaz de usuario. Ahora, estamos listos para conectar la captura de cambios en nuestra interfaz de usuario de búsqueda y almacenarlos como parámetros de consulta en nuestra URL.

Capturar filtros de búsqueda como parámetros de consulta

Ahora que tenemos nuestra interfaz de usuario base configurada, podemos comenzar a administrar nuestros parámetros de consulta. Para hacerlo, agregaremos algunos detectores de eventos de JavaScript a nuestra interfaz de usuario para que podamos obtener los valores más recientes establecidos por el usuario:

/ui/pages/index/index.js

import ui from '@joystick.js/ui';
import queryString from 'query-string';

const Index = ui.component({
  state: { ... },
  methods: {
    handleUpdateQueryParams: (param = '', value = '') => {
      const existingQueryParams = queryString.parse(location.search);
      const updatedQueryParams = queryString.stringify({
        ...existingQueryParams,
        [param]: value,
      });

      window.history.pushState('', '', `?${updatedQueryParams}`);
    },
    handleClearQueryParams: (component = {}) => {
      window.history.pushState('', '', `${location.origin}${location.pathname}`);
      component.methods.handleSetStateFromQueryParams();
    },
  },
  css: `...`,
  events: {
    'keyup [name="search"]': (event, component = {}) => {
      component.methods.handleUpdateQueryParams('search', event.target.value);
    },
    'change [name="category"]': (event, component = {}) => {
      component.methods.handleUpdateQueryParams('category', event.target.value);
    },
    'change [name="status"]': (event, component = {}) => {
      component.methods.handleUpdateQueryParams('status', event.target.value);
    },
    'change [type="checkbox"]': (event, component = {}) => {
      component.methods.handleUpdateQueryParams(event.target.name, event.target.checked);
    },
    'click .clear': (event, component = {}) => {
      event.preventDefault();
      component.methods.handleClearQueryParams();
    },
  },
  render: ({ state }) => {
    return `
      <div class="search">
        ...
      </div>
    `;
  },
});

export default Index;

Arriba, hemos agregado dos nuevas propiedades a las opciones de nuestro componente:events y methods . Centrándose en events , aquí, Joystick nos ayuda a escuchar eventos DOM de JavaScript en elementos representados por nuestro componente. Cada evento se define como una propiedad en el objeto pasado a events donde el nombre de la propiedad es una cadena que describe el tipo de evento DOM para escuchar y el elemento dentro de nuestro componente para escuchar el evento on .

A la propiedad, le asignamos una función que debe llamarse cuando se detecta ese evento en el elemento especificado. Aquí, hemos agregado oyentes para cada una de nuestras entradas relacionadas con la búsqueda (a excepción de las entradas de casilla de verificación que solo escuchamos genéricamente en entradas con un tipo de checkbox ).

Tenga en cuenta que el pato extraño aquí es el search entrada de texto. Aquí, queremos escuchar el keyup evento en la entrada ya que queremos capturar cada cambio en la entrada (si escuchamos un change evento como hacemos con los demás, solo se activará después de que el usuario haya "borroso" o haya hecho clic fuera de la entrada).

Dentro de todos los detectores de eventos (excepto el último que cubriremos en un momento), estamos llamando a component.methods.handleUpdateQueryParams() . A la función de devolución de llamada de un detector de eventos, Joystick pasa dos valores:event y component . event siendo el evento DOM de JavaScript sin procesar que se disparó y component siendo la instancia del componente actual (similar a lo que vimos en render() )—el = {} parte después de component Aquí estamos nosotros definiendo un valor predeterminado, una característica principal de JavaScript, al que recurrir en caso de que component no está definido (esto nunca será cierto ya que es automático; considere agregar esto como una fuerza del hábito).

Del component instancia, queremos acceder a un método definido en el methods objeto (donde podemos almacenar varios métodos en nuestra instancia de componente). Aquí, llamamos a un método definido anteriormente, handleUpdateQueryParams() .

Arriba, hemos agregado una importación del queryString paquete que instalamos anteriormente que nos ayudará a analizar los parámetros de consulta existentes en la URL y preparar nuestros valores para adición a la URL.

Dentro de handleUpdateQueryParams() , debemos anticipar los parámetros de consulta existentes en nuestra URL que estamos agregando, por lo tanto, comenzamos tomando los parámetros de consulta existentes y analizándolos en un objeto con queryString.parse() . Aquí, location.search es el valor del navegador global que contiene la cadena de consulta actual como ?someParam=value . Cuando pasamos ese valor a queryString.parse() obtenemos un objeto JavaScript como { someParam: 'value' } .

Con eso, creamos otra variable updatedQueryParams que se establece en una llamada a queryString.stringify() y pasamos un objeto que queremos volver a convertir en una cadena de consulta como ?someParam=value .

En ese objeto, usando JavaScript ... operador de propagación, primero "desempaquetamos" o extendemos cualquier parámetro de consulta existente y luego lo seguimos inmediatamente con [param]: value donde param es el nombre del parámetro que queremos actualizar (pasado como primer argumento a handleUpdateQueryParams() ) y value siendo el valor que queremos establecer para ese parámetro, establecido a través del segundo argumento pasado a handleUpdateQueryParams() . El [param] la sintaxis aquí está usando la notación de corchetes de JavaScript para decir "establece dinámicamente el nombre de la propiedad en el valor de param argumento."

Si miramos hacia abajo en nuestros controladores de eventos para ver cómo se llama esto, pasamos el param ya sea como una cadena o en el caso de nuestras entradas de casilla de verificación, como el event.target.name valor o el name atributo de la casilla de verificación que activa el evento.

Con updatedQueryParams compilado, a continuación, para actualizar nuestra URL, llamamos al global window.history.pushState() pasando una actualización que queremos aplicar a la URL. Aquí, history.pushState() es una función que actualiza el historial de nuestro navegador pero no activa una actualización del navegador (como esperaríamos si configuramos manualmente el location.search valor directamente).

Es cierto que la API para history.pushState() es un poco confuso (como se indica en este artículo de MDN sobre la función aquí). Para los primeros dos valores, solo pasamos cadenas vacías (consulte el enlace anterior en MDN si tiene curiosidad sobre para qué sirven) y para el tercer argumento, pasamos la URL que queremos "empujar" en el historial del navegador.

En este caso, no queremos modificar la URL en sí, solo los parámetros de consulta, por lo que pasamos una cadena que contiene un ? que denota el comienzo de los parámetros de consulta en una URL y el valor devuelto por queryString.stringify() en updatedQueryParams .

Eso es todo. Ahora, si comenzamos a realizar cambios en nuestra interfaz de usuario, deberíamos ver que nuestra URL comienza a actualizarse dinámicamente con los valores de entrada de nuestra interfaz de usuario de búsqueda.

Antes de continuar, muy rápido, llamando la atención sobre el click .clear detector de eventos y posterior llamada a methods.handleClearQueryParams() , aquí estamos haciendo lo que sugiere el código:borrar cualquier parámetro de consulta que hayamos establecido en la URL cuando el usuario hace clic en el enlace "Borrar" al final de nuestra interfaz de usuario de búsqueda.

Para hacerlo, eventualmente llamamos a history.pushState() , esta vez pasando la combinación del actual location.origin (por ejemplo, http://localhost:2600 ) con el location.pathname actual (por ejemplo, / o /listings/123 ). Esto borra efectivamente todos los parámetros de consulta en la URL y los reduce a solo la URL base para la página actual.

Después de esto, estamos llamando a otro método que aún tenemos que definir:methods.handleSetStateFromQueryParams() . Veremos cómo toma forma esto en la siguiente y última sección.

Recargar filtros de búsqueda cuando se carga la página

Esta parte es bastante sencilla. Ahora que tenemos nuestros parámetros de consulta en nuestra URL, queremos tener en cuenta esos parámetros cada vez que se carga nuestra página. Recuerde, queremos poder alejarnos de esta página, volver y hacer que nuestra interfaz de usuario de búsqueda "recargue" los valores de búsqueda del usuario desde la URL.

/ui/pages/index/index.js

import ui from '@joystick.js/ui';
import queryString from 'query-string';

const Index = ui.component({
  state: { ... },
  lifecycle: {
    onMount: (component = {}) => {
      component.methods.handleSetStateFromQueryParams();
    },
  },
  methods: {
    handleSetStateFromQueryParams: (component = {}) => {
      const queryParams = queryString.parse(location.search);
      component.setState({
        search: queryParams?.search || '',
        category: queryParams?.category || 'house',
        status: queryParams?.status || 'forSale',
        hasGarage: queryParams?.hasGarage && queryParams?.hasGarage === 'true' || false,
        hasCentralAir: queryParams?.hasCentralAir && queryParams?.hasCentralAir === 'true' || false,
        hasPool: queryParams?.hasPool && queryParams?.hasPool === 'true' || false,
      });
    },
    handleUpdateQueryParams: (param = '', value = '') => { ... },
    handleClearQueryParams: (component = {}) => {
      window.history.pushState('', '', `${location.origin}${location.pathname}`);
      component.methods.handleSetStateFromQueryParams();
    },
  },
  css: `...`,
  events: { ... },
  render: ({ state }) => {
    return `
      <div class="search">
        ...
      </div>
    `;
  },
});

export default Index;

Ultima parte. Arriba, hemos agregado una propiedad adicional a las opciones de nuestro componente lifecycle y en el objeto pasado a eso, hemos definido una función onMount tomando en el component instancia como primer argumento.

Aquí, decimos "cuando este componente se monta (carga) en el navegador, llama al methods.handleSetStateFromQueryParams() función. La idea es lo que cabría esperar:cargar el conjunto actual de parámetros de consulta de la URL de nuevo en el estado de nuestro componente cuando se carga la página.

Centrándose en handleSetStateFromQueryParams() , el trabajo aquí es bastante simple. Primero, queremos obtener los parámetros de consulta como un objeto queryParams llamando al queryString.parse(location.search) . Esto es similar a lo que vimos antes, tomando el ?someParam=value formulario de nuestros parámetros de consulta y convertirlo en un objeto JavaScript como { someParam: 'value' } .

Con ese objeto queryParams , llamamos a component.setState() para actualizar dinámicamente el estado de nuestro componente. Aquí, estamos configurando cada uno de los valores que especificamos en el state predeterminado de nuestro componente más temprano. Para cada valor, intentamos acceder a ese parámetro desde el queryParams objeto. Si existe, lo usamos, y si no, usamos JavaScript o || operador para decir "usar este valor en su lugar". Aquí, el "en su lugar" simplemente vuelve a los mismos valores que establecimos en el estado predeterminado anteriormente.

¡Eso es todo! Ahora, cuando establecemos algunos valores de búsqueda y actualizamos la página, nuestros parámetros de consulta permanecerán y se restablecerán automáticamente en nuestra interfaz de usuario si actualizamos la página. Si hacemos clic en el listado falso en nuestra lista para ir a su página de detalles y luego hacemos clic en "atrás" en el navegador, nuestros parámetros de consulta seguirán existiendo en la URL y se volverán a cargar en la interfaz de usuario.

Terminando

En este tutorial, aprendimos cómo configurar dinámicamente los parámetros de consulta en el navegador. Aprendimos cómo crear una interfaz de usuario de búsqueda dinámica y simple que almacenaba los parámetros de búsqueda del usuario en la URL y, al volver a cargar la página, cómo cargar esos parámetros de la URL nuevamente en nuestra interfaz de usuario. Para hacerlo, aprendimos a usar las diversas funciones de un componente Joystick junto con el query-string paquete para ayudarnos a codificar y decodificar los parámetros de consulta en nuestra URL.