Need a Website or app? Hire an experienced team of Web and Mobile developers with us.
Free Consultation

Syncing query parameters with react state

How to sync query parameters with react state.

Posted by Dhruw Lalan on 03 Jun 2022
Syncing query parameters with react state

It is very common nowadays that you might want to store some information for your react app directly into the URL in the form of query parameters so that the state of the app remains the same and in sync with the URL.

To achieve this, we will need a way to set and fetch query parameters. We will also need to keep a watcher on them so that our state is in sync with the latest query parameters. We can make use of react hooks and create a custom hook called useQueryState.jsx to achieve this.

Let's start by creating our hook. Firstly, to perform query parameter operations with ease, we can make use of the qs library. Let's see what our end goal should look like before creating the hook.

// https://www.your-app-url.com/?foo=bar

const [foo, setFoo] = useQueryState("foo")

console.log(foo) // 'bar'

setFoo("baz")

// url should changed to: https://www.your-app-url.com/?foo=baz

console.log(foo) // 'baz'

Lets now create the useQueryState hook:

import { useCallback } from "react"
import { useHistory, useLocation } from "react-router-dom"

import qs from "qs"

export const useQueryState = query => {
  const location = useLocation()
  const history = useHistory()

  const setQuery = useCallback(
    value => {
      const existingQueries = qs.parse(location.search, {
        ignoreQueryPrefix: true,
      })

      const queryString = qs.stringify(
        { ...existingQueries, [query]: value },
        { skipNulls: true }
      )

      history.push(`${location.pathname}?${queryString}`)
    },
    [history, location, query]
  )

  return [
    qs.parse(location.search, { ignoreQueryPrefix: true })[query],
    setQuery,
  ]
}

Let's take a quick look at what’s going on inside the hook one by one.

  1. We make use of useHistory to update our URL without refreshing the page using its push method.
  2. We make use of useLocation to get the current URL’s pathname as well as the current query parameters.
  3. Our hook takes query as the argument, which is the name of the query parameter that we want to work with and be in sync with.
  4. Finally, we have our setQuery function, which is responsible for updating the query parameters.

This setQuery function is the way through which we will be updating our query parameters. We will be using it inside our react components and will call this function whenever we want to update our query parameters. When the function is called, it does the following things:

  1. It grabs all the current query parameters and stores them in the existingQueries variable.
  2. It changes the value of the query parameter with the value passed into the setQuery function and spreads it within the existingQueries object, from which the queryString gets created.
  3. Finally, it pushes the newly created and updated queryString string into the URL with the help of the history.push() function.

Let's take a quick example of an app that has two input elements: one is a date component and the other is a select component. Whenever one of the values of the input is changed, we will be updating the query parameters with the input's latest value and also the state of the app remains in sync with the query parameters when the app is refreshed.

import React, { useState } from "react"
import DatePicker from "react-datepicker"
import Select from "react-select"
import { format, parse } from "date-fns"

import { useQueryState } from "./useQueryState"

import "react-datepicker/dist/react-datepicker.css"
import "./style.css"

const options = [
  { value: "chocolate", label: "Chocolate" },
  { value: "strawberry", label: "Strawberry" },
  { value: "vanilla", label: "Vanilla" },
]

export default function App() {
  const [date, setDate] = useQueryState("date")
  const [option, setOption] = useQueryState("options")

  const handleSelect = option => {
    setOption(option?.value || null)
  }

  const handleDate = date => {
    setDate(format(date, "MM-dd-yyyy"))
  }

  return (
    <div>
      <h1>sync query params demo</h1>
      <div>
        <div>
          <DatePicker
            selected={date ? parse(date, "MM-dd-yyyy", new Date()) : new Date()}
            onChange={handleDate}
          />
        </div>
        <div>
          <Select
            isClearable
            value={options.find(o => o.value === option)}
            onChange={handleSelect}
            options={options}
          />
        </div>
      </div>
    </div>
  )
}

You can find the above working example here and you can try to update the values of the inputs and see how the URL’s query parameters are changed accordingly, keeping the app state in sync with the query parameters.

Thank you!


Need a Website or app? Hire an experienced team of Web and Mobile developers with us.
Free Consultation

Related Services.



Hire ReactJS Developers
Hire Gatsby Developers
Hire NextJS Developers

We support the Open Source community.



Have a Project in mind?