State in url

State management and URL sync

Store complex state in query parameters; imagine JSON in a browser URL, while keeping types and structure of data.

useUrlState - demo with react-router

Try to type something
First client component
Other client component

Types and structure of data are presered

{
name: string
age: undefinedundefined
agree_to_terms: falseboolean
tags: []
}

Instructions for:

Quick start

1. Define the state
state
export const form: Form = {
  name: '',
  age: undefined,
  agree_to_terms: false,
  tags: [],
};

// use `Type` not `Interface`!
type Form = {
  name: string;
  age?: number;
  agree_to_terms: boolean;
  tags: { id: string; value: { text: string; time: Date } }[];
};
2. Use it in any components
ComponentA
import { useUrlState } from 'state-in-url/react-router';
import { form } from './form';

export const ComponentA = () => {
  // see docs for all possible params https://github.com/asmyshlyaev177/state-in-url/tree/master/packages/urlstate/react-router/useUrlState
  const { urlState, setUrl, setState } = useUrlState(form);

  return <>
    <input
      id="name"
      value={urlState.name} 
      onChange={(ev) => setUrl({ name: ev.target.value })}
      />
    // OR can update state immediately but sync change to url as needed
    <input
      value={urlState.name}
      onChange={(ev) => { setState(curr => ({ ...curr, name: ev.target.value })) }}
      onBlur={() => setUrl()}
    />
    </>
};
ComponentB
import { useUrlState } from 'state-in-url/react-router';
import { form } from './form';

export const ComponentB = () => {
  const { urlState } = useUrlState(form);

// will be defaultValue from `form` if not in url, no need to check
  return <div>name: {urlState.name}</div>
};
3. Can create self-sufficient hook to manage slice of some state.
useFormState - custom hook
import React from 'react';
import { useUrlState } from 'state-in-url/react-router';

const form: Form={
  name: '',
  age: undefined,
  agree_to_terms: false,
  tags: [],
};

type Form = {
  name: string;
  age?: number;
  agree_to_terms: boolean;
  tags: {id: string; value: {text: string; time: Date } }[];
};

export const useFormState = () => {
  const { urlState, setUrl: setUrlBase, reset } = useUrlState(form);

  // first navigation will push new history entry
  // all following will just replace that entry
  // this way will have history with only 2 entries - ['/url', '/url?key=param']

  const replace = React.useRef(false);
  const setUrl = React.useCallback((
      state: Parameters<typeof setUrlBase>[0],
      opts?: Parameters<typeof setUrlBase>[1]
    ) => {
      setUrlBase(state, { replace: replace.current, ...opts });
      replace.current = true;
  }, [setUrlBase]);

  return { urlState, setUrl, resetUrl: reset };
};

Motivation

Main goal is to provide state management with URI and good developer experience, there are many similar libraries, but non of them are easy enough to use, or lack functionality.

state-in-url provides useUrlState hook for Next.js/react-router. With it you can store state easily without a lot of boilerplate, and implement Deep Links pattern for your App.
No need to wrap components in a provider, can share data between unrelated client components. API is very similar to React.useState.

Structure and types are preserved, with full Typescript support.

Code quality

Library developed with best practices and TDD in mind, and it's ready for production use.

Other frameworks or pure JS

There are more hooks and helpers to deal with serialization/decoding of data.
Check out GitHub page. Give me a star.

Share this on social networks to help the library, purely voluntarily :)

Uneed Embed Badge