Gegevens cachen met behulp van URL-queryparameters in JavaScript

Hoe u tijdelijk gegevens opslaat in de queryparameters van een URL en deze ophaalt en parseert voor gebruik in uw gebruikersinterface.

Aan de slag

Voor deze tutorial gaan we het full-stack JavaScript-framework van CheatCode, Joystick, gebruiken. Joystick brengt een front-end UI-framework samen met een Node.js-back-end voor het bouwen van apps.

Om te beginnen willen we Joystick via NPM installeren. Zorg ervoor dat u Node.js 16+ gebruikt voordat u installeert om compatibiliteit te garanderen (lees deze tutorial eerst als u wilt leren hoe u Node.js installeert of meerdere versies op uw computer uitvoert):

Terminal

npm i -g @joystick.js/cli

Hiermee wordt Joystick wereldwijd op uw computer geïnstalleerd. Na de installatie gaan we een nieuw project maken:

Terminal

joystick create app

Na een paar seconden ziet u een bericht dat u bent uitgelogd op cd in uw nieuwe project en voer joystick start . uit . Voordat u joystick start uitvoert , we moeten één pakket installeren, query-string :

Terminal

cd app && npm i query-string

Dit pakket helpt ons bij het ontleden en instellen van onze queryparameters. Nadat dat is geïnstalleerd, ga je gang en start je de server op:

Terminal

joystick start

Hierna zou je app moeten werken en zijn we klaar om aan de slag te gaan.

Wat globale CSS toevoegen

Om onze demo beter te contextualiseren, gaan we tijdens de hele tutorial CSS toevoegen. Om te beginnen, moeten we wat globale CSS toevoegen die de algemene weergave van onze pagina's gaat afhandelen:

/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;
  }
}

Wanneer u dit bestand opent, wordt standaard alleen de CSS voor de body label zal bestaan. De details hier zijn niet zo belangrijk, maar wat we doen is het toevoegen van enkele "reset" -stijlen voor alle HTML-elementen in de browser (het verwijderen van de standaard browser-CSS die extra marges en opvulling toevoegt en verandert hoe elementen in de doos stromen model) en een .container klasse waarmee we gemakkelijk een gecentreerde <div></div> . kunnen maken voor het verpakken van inhoud.

Dat is alles wat we hier nodig hebben. We zullen later meer CSS toevoegen op het niveau van de individuele componenten. Vervolgens moeten we een route uitstippelen voor een dummy-pagina die we zullen gebruiken om onze queryparameters te testen.

Een route toevoegen om naar om te leiden voor het testen van parameters

In een Joystick-app worden alle routes op één plek op de server gedefinieerd:/index.server.js . Laten we dat nu openen en een route toevoegen voor een dummy-pagina waarnaar we kunnen doorverwijzen en controleren of onze queryparameters werken zoals verwacht:

/index.server.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,
        },
      });
    },
  },
});

Toen je joystick start . uitvoerde eerder uit de root van je app, dit is het bestand dat Joystick heeft opgestart. Hier, de node.app() functie start achter de schermen een nieuwe Node.js-toepassing op met behulp van Express.js. Om uit te drukken, de routes object dat wordt gedefinieerd op het options-object dat is doorgegeven aan node.app() wordt overgedragen.

Standaard zien we op dit object de / en * routes worden gedefinieerd. Hierboven hebben we een nieuwe route toegevoegd /listings/:listingId . Voor onze app bouwen we een nep-gebruikersinterface voor het zoeken naar onroerend goed waar gebruikers enkele zoekparameters kunnen aanpassen en vermeldingen kunnen bekijken.

Hier creëren we de route voor een nep-het laadt geen echte gegevens, alleen wat statische dummy-gegevens-lijstpagina waarnaar de gebruiker kan doorverwijzen. Het idee is dat we een aantal query-params zullen instellen op de URL op de / (index) route en laat de gebruiker vervolgens klikken op een link naar deze /listings/:listingId bladzijde. Als ze dat doen, zullen de queryparameters die we hebben ingesteld "verdwijnen". Als ze teruggaan, verwachten we dat die queryparameters worden hersteld.

Binnen de route hier roepen we een functie aan op de res object, res.render() wat een speciale functie is die Joystick toevoegt aan de standaard Express res object. Deze functie is ontworpen om het pad naar een Joystick-component in onze app te nemen en deze op de pagina weer te geven.

Hier gaan we ervan uit dat we een pagina hebben op /ui/pages/listing/index.js . Laten we dat nu gaan bekabelen.

Een valse vermeldingspagina bedraden

Deze is snel. We geven hier niet zoveel om de pagina zelf, alleen dat deze voor ons bestaat om de gebruiker naar door te verwijzen.

/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;

Hier maken we een Joystick-component door de .component() . aan te roepen functie gedefinieerd op de ui object dat we importeren uit de @joystick.js/ui pakket. Aan die functie geven we een object met opties door om onze component te definiëren.

Onderaan beginnen we met een render() functie die onze component de HTML vertelt die we voor onze component willen weergeven. Omdat we hier geen werkende pagina nodig hebben, retourneren we gewoon een reeks gewone HTML met wat hardgecodeerde gegevens. Merk op dat de house.jpg afbeelding die hier wordt weergegeven, kan hier worden gedownload van onze S3-bucket. Dit moet in de /public . worden geplaatst map in de hoofdmap van het project.

Daarnaast voegen we, zoals we eerder hebben aangegeven, wat CSS toe. Om dit te doen, hebben we op een Joystick-component de css optie waaraan we een reeks CSS kunnen doorgeven. Joystick stuurt deze CSS automatisch naar deze component om te voorkomen dat de stijlen naar andere componenten worden gelekt.

Dat is het hier. Nogmaals, dit is slechts een dummy-component die ons helpt bij het testen van de logica van queryparameters die we in de volgende sectie zullen opzetten.

Een nep-zoek-UI bedraden met filters en resultatenpagina

Hoewel er veel gaande is in dit onderdeel, is het deel waar we ons op willen concentreren de logica voor het beheren van onze queryparameters. Om daar te komen, laten we eerst de geraamte gebruikersinterface voor onze component uitbouwen en vervolgens de eigenlijke logica doorspitten om het werkend te krijgen.

Hoewel we het niet eerder hebben besproken, gaan we hier de bestaande inhoud van de /ui/pages/index/index.js overschrijven bestand:

/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;

Hierboven krijgen we de kern-HTML en CSS op pagina voor onze gebruikersinterface. Nogmaals, ons doel is om een ​​pseudo-zoek-UI te hebben waar de gebruiker enkele zoekparameters kan instellen en een lijst met resultaten op de pagina kan zien. Hier bouwen we die kern-UI uit en stylen we deze op. Nadat we dit hebben toegevoegd, als we http://localhost:2600/ . bezoeken (negeer de 2605 in de onderstaande schermafbeelding (dit was alleen om te testen tijdens het schrijven) in onze browser, zouden we zoiets als dit moeten zien:

Laten we vervolgens een "standaard" status instellen voor onze zoek-UI (we verwijzen naar alles in de kop of het bovenste gedeelte van de UI als de "zoek-UI").

/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;

Op een Joystick-component kunnen we een state . doorgeven optie die is toegewezen aan een object met eigenschappen die we standaard willen toewijzen aan de interne status van onze component (d.w.z. wanneer de component voor het eerst wordt geladen). Hier creëren we enkele standaardinstellingen die we willen gebruiken voor onze zoek-UI.

Het belangrijkste deel hier, terug in de render() functie, is dat we een argument hebben toegevoegd aan onze render() functie waarvan we verwachten dat het een object is dat we kunnen destructureren om specifieke eigenschappen te "plukken" en deze toe te wijzen aan variabelen met dezelfde naam in de huidige scope/context. Het object dat we hier verwachten is de component instantie (d.w.z. het onderdeel waar we momenteel aan werken, zoals het in het geheugen bestaat).

In dat geval verwachten we toegang te hebben tot de huidige state waarde. "Status" verwijst in dit geval naar de visuele staat van onze gebruikersinterface. De waarden op de state objecten zijn bedoeld als een middel om deze visuele toestand on-the-fly te verbeteren.

Hier nemen we dat state object om te verwijzen naar de waarden om onze zoek-UI te vullen. We hebben drie soorten invoer in onze gebruikersinterface:

  1. input dat is een platte tekstinvoer die wordt gebruikt voor het invoeren van een reeks zoektekst.
  2. select die wordt gebruikt voor onze vermelding "categorie" en "status" invoer.
  3. checkbox die wordt gebruikt voor de selectievakjes voor onze voorzieningen.

In onze HTML verwijzen we naar deze waarden met behulp van JavaScript-tekenreeksinterpolatie (een functie op taalniveau voor het insluiten/evalueren van JavaScript in een tekenreeks). We kunnen dit doen omdat de waarde die we retourneren van de render() . van onze component functie is een string.

Afhankelijk van het type invoer dat we weergeven, gebruiken we de bijbehorende statuswaarde iets anders. Voor onze zoekinvoer in platte tekst kunnen we gewoon een value . instellen attribuut gelijk aan de waarde van state.search .

Voor onze selecte <select> invoer zetten we beide een value attribuut op de hoofd <select> tag en een voorwaardelijke selected attribuut voor elke optie in die <select> lijst (belangrijk alsof we dit niet doen, de huidige waarde van de invoer wordt niet weergegeven als geselecteerd zonder dit kenmerk).

Ten slotte voegen we voor onze checkbox-invoer voorwaardelijk een checked . toe attribuutwaarde gebaseerd op de corresponderende state waarde voor elke invoer.

Dit geeft ons de basis van onze gebruikersinterface. Nu zijn we klaar om het vastleggen van wijzigingen in onze zoek-UI vast te leggen en ze op te slaan als queryparameters in onze URL.

Zoekfilters vastleggen als queryparameters

Nu we onze basis-UI-set hebben, kunnen we beginnen met het beheren van onze queryparameters. Om dit te doen, gaan we enkele JavaScript-gebeurtenislisteners toevoegen aan onze gebruikersinterface, zodat we de nieuwste waarden kunnen pakken zoals ze zijn ingesteld door de gebruiker:

/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;

Hierboven hebben we twee nieuwe eigenschappen toegevoegd aan de opties van onze component:events en methods . Focussen op events , hier helpt Joystick ons ​​om te luisteren naar JavaScript DOM-gebeurtenissen op elementen die door onze component worden weergegeven. Elke gebeurtenis wordt gedefinieerd als een eigenschap van het object dat wordt doorgegeven aan events waarbij de eigenschapsnaam een ​​tekenreeks is die het type DOM-gebeurtenis beschrijft waarnaar moet worden geluisterd en het element in onze component om te luisteren naar de gebeurtenis op .

Aan de eigenschap wijzen we een functie toe die moet worden aangeroepen wanneer die gebeurtenis wordt gedetecteerd op het opgegeven element. Hier hebben we luisteraars toegevoegd voor elk van onze zoekgerelateerde inputs (behalve voor de checkbox inputs waar we gewoon in het algemeen naar luisteren op inputs met een type checkbox ).

Merk op dat de vreemde eend in de bijt de search . is tekst invoer. Hier willen we luisteren naar de keyup gebeurtenis op de invoer omdat we elke wijziging aan de invoer willen vastleggen (als we luisteren naar een change gebeurtenis zoals wij de anderen doen, wordt deze alleen geactiveerd nadat de gebruiker "wazig" heeft gemaakt of de invoer heeft verlaten).

Binnen alle gebeurtenislisteners (behalve de laatste die we zo zullen bespreken), bellen we naar component.methods.handleUpdateQueryParams() . Aan de callback-functie van een gebeurtenislistener geeft Joystick twee waarden door:event en component . event zijnde de onbewerkte JavaScript DOM-gebeurtenis die is geactiveerd en component zijnde de huidige componentinstantie (vergelijkbaar met wat we zagen in render() )—de = {} deel na component hier definiëren we een standaardwaarde - een kernfunctie van JavaScript - om op terug te vallen in het geval dat component is niet gedefinieerd (dit zal nooit waar zijn omdat het automatisch gaat - overweeg om dit een gewoontekracht toe te voegen).

Van de component we willen bijvoorbeeld toegang krijgen tot een methode die is gedefinieerd op de methods object (waar we diverse methoden op onze componentinstantie kunnen opslaan). Hier roepen we een methode aan die hierboven is gedefinieerd, handleUpdateQueryParams() .

Bovenaan hebben we een import van de queryString . toegevoegd pakket dat we eerder hebben geïnstalleerd en dat ons zal helpen de bestaande queryparameters in de URL te ontleden en onze waarden voor te bereiden voor toevoeging naar de URL.

Binnenkant van handleUpdateQueryParams() , we moeten anticiperen op bestaande queryparameters in onze URL waaraan we toevoegen, dus we beginnen met het grijpen van alle bestaande queryparameters en deze te parseren in een object met queryString.parse() . Hier, location.search is de globale browserwaarde die de huidige queryreeks bevat, zoals ?someParam=value . Wanneer we die waarde doorgeven aan queryString.parse() we krijgen een JavaScript-object terug zoals { someParam: 'value' } .

Daarmee creëren we een andere variabele updatedQueryParams die is ingesteld op een oproep naar queryString.stringify() en gaf een object door dat we terug willen converteren naar een queryreeks zoals ?someParam=value .

Op dat object, met behulp van de JavaScript ... spread-operator, "uitpakken" of verspreiden we eerst alle bestaande queryparameters en volgen deze dan onmiddellijk met [param]: value waar param is de naam van de parameter die we willen bijwerken (doorgegeven als het eerste argument aan handleUpdateQueryParams() ) en value zijnde de waarde die we willen instellen voor die parameter—set via het tweede argument doorgegeven aan handleUpdateQueryParams() . De [param] syntaxis hier gebruikt JavaScript-haakjesnotatie om te zeggen "stel de eigenschapsnaam dynamisch in op de waarde van de param argument."

Als we in onze event-handlers naar beneden kijken om te zien hoe dit wordt genoemd, geven we de param door ofwel als een string of in het geval van onze checkbox-invoer, als de event.target.name waarde of de name attribuut van de checkbox die de gebeurtenis activeert.

Met updatedQueryParams gecompileerd, vervolgens, om onze URL bij te werken, bellen we naar de globale window.history.pushState() het doorgeven van een update die we willen toepassen op de URL. Hier, history.pushState() is een functie die de geschiedenis van onze browser bijwerkt maar activeert geen browservernieuwing (zoals we zouden verwachten als we de location.search handmatig instellen waarde direct).

Toegegeven, de API voor history.pushState() is een beetje verwarrend (zoals vermeld in dit MDN-artikel over de functie hier). Voor de eerste twee waarden geven we alleen lege strings door (zie de vorige link op MDN als je benieuwd bent waar deze voor zijn) en voor het derde argument geven we de URL door die we naar de browsergeschiedenis willen "pushen".

In dit geval willen we de URL zelf niet wijzigen, alleen de queryparameters, dus geven we een string door met een ? die het begin van de queryparameters in een URL aangeeft en de waarde die wordt geretourneerd door queryString.stringify() in updatedQueryParams .

Dat is het. Als we nu wijzigingen gaan aanbrengen in onze gebruikersinterface, zouden we moeten zien dat onze URL dynamisch wordt bijgewerkt met de invoerwaarden van onze zoekinterface.

Voordat we verder gaan, heel snel, de aandacht vestigen op de click .clear gebeurtenislistener en daaropvolgende oproep naar methods.handleClearQueryParams() , hier doen we wat de code suggereert:het wissen van alle zoekparameters die we op de URL hebben ingesteld wanneer de gebruiker op de link 'Wissen' aan het einde van onze zoekinterface klikt.

Om dit te doen, bellen we uiteindelijk naar history.pushState() , deze keer passeren de combinatie van de huidige location.origin (bijv. http://localhost:2600 ) met de huidige location.pathname (bijv. / of /listings/123 ). Hiermee worden effectief alle queryparameters in de URL gewist en wordt deze teruggebracht tot alleen de basis-URL voor de huidige pagina.

Hierna bellen we naar een andere methode die we nog moeten definiëren:methods.handleSetStateFromQueryParams() . We zullen zien hoe dit vorm krijgt in de volgende - en laatste - sectie.

Zoekfilters opnieuw laden wanneer pagina wordt geladen

Dit deel is vrij eenvoudig. Nu we onze queryparameters in onze URL hebben, willen we rekening houden met die parameters wanneer onze pagina wordt geladen. Onthoud dat we deze pagina willen verlaten, terugkomen en onze zoek-UI de zoekwaarden van de gebruiker willen laten "herladen" vanaf de 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;

Laatste deel. Hierboven hebben we een extra eigenschap toegevoegd aan onze componentopties lifecycle en op het object dat daaraan is doorgegeven, hebben we een functie gedefinieerd onMount het innemen van de component instantie als het eerste argument.

Hier zeggen we "wanneer deze componenten worden geactiveerd (laadt) in de browser, bel dan naar de methods.handleSetStateFromQueryParams() functie. Het idee is wat je zou verwachten:om de huidige set queryparameters van de URL terug te laden naar de status van onze component wanneer de pagina wordt geladen.

Focussen op handleSetStateFromQueryParams() , het werk hier is vrij eenvoudig. Eerst willen we de queryparameters als een object queryParams . krijgen door te bellen naar queryString.parse(location.search) . Dit is vergelijkbaar met wat we eerder zagen, met de ?someParam=value vorm van onze queryparameters en converteert deze naar een JavaScript-object zoals { someParam: 'value' } .

Met dat object queryParams , we bellen naar component.setState() om de status van onze component dynamisch bij te werken. Hier stellen we elk van de waarden in die we hebben opgegeven in de standaard state van onze component eerder. Voor elke waarde proberen we toegang te krijgen tot die parameter vanuit de queryParams object. Als het bestaat, gebruiken we het, en zo niet, gebruiken we JavaScript of || operator om te zeggen "gebruik deze waarde in plaats daarvan". Hier valt de "in plaats daarvan" gewoon terug naar dezelfde waarden die we eerder op de standaardstatus hadden ingesteld.

Dat is het! Wanneer we nu enkele zoekwaarden instellen en de pagina vernieuwen, blijven onze queryparameters behouden en worden deze automatisch teruggezet in onze gebruikersinterface als we de pagina vernieuwen. Als we op de nepvermelding in onze lijst klikken om naar de detailpagina te gaan en vervolgens op "Terug" in de browser klikken, zullen onze queryparameters nog steeds bestaan ​​in de URL en weer in de gebruikersinterface worden geladen.

Afsluiten

In deze zelfstudie hebben we geleerd hoe u queryparameters dynamisch in de browser kunt instellen. We leerden hoe we een eenvoudige, dynamische zoek-UI konden maken die de zoekparameters van de gebruiker in de URL opsloeg en bij het herladen van de pagina, hoe we die parameters van de URL terug in onze gebruikersinterface konden laden. Om dit te doen, hebben we geleerd hoe we de verschillende functies van een Joystick-component kunnen gebruiken in combinatie met de query-string pakket om ons te helpen de queryparameters in onze URL te coderen en decoderen.