url-state-hook v1.2.3
url-state-hook
This is a React hook that is very similar to the built-in React.useState()
, except that it mirrors the current state in the url as a query parameter. When a component that is using this hook mounts, if the url already contains a query-parameter value for the hook, it will use that as the initial state.
This allows page state to be maintained over various sessions, page refreshes, or back button navigation.
By default this hook it set up to use the default React Router from react-router-dom
, but it can be configured to use other routers as well.
This is not a global state management hook
Install
NPM
npm install --save url-state-hook
Yarn
yarn add url-state-hook
Live Demo
https://williammetcalf.github.io/url-state-hook/
Basic Usage
import useUrlState from "url-state-hook";
const Example = () => {
const [value, setValue] = useUrlState("s", "default value");
return (
<div>
<input value={value} onChange={e => setValue(e.target.value)} />
</div>
);
};
Basic Array Usage
This package also exports a useUrlArrayState
to handle array states. This is really just a wrapper around the default useUrlState
with a customized decode
option to handle deserializing the array.
import { useUrlArrayState } from "./use-state-hook";
const Example = () => {
const [arrayState, setArrayState] = useUrlArrayState("arr", []);
return (
<div>
<ul>
{arrayState.map((val, idx) => (
<li key={idx}>
{val}
<button
onClick={() => {
const newState = [...arrayState];
newState.splice(idx, 1);
setArrayState(newState);
}}
>
x
</button>
</li>
))}
</ul>
<input
onKeyPress={e => {
if (e.key === "Enter") {
const newState = [...arrayState];
newState.push(e.target.value);
e.target.value = "";
setArrayState(newState);
}
}}
/>
</div>
);
};
Nextjs Example
By default useUrlState
uses the built in React Router, but by configuring the options
parameter other routers can be used instead. To do this, you must set the options.useCurrentUrlHook
and options.updateUrlFn
values. For example, here is a wrapper that can be used to make useUrlState
work with Nextjs.
use-next-js-url-state.ts
import Router, { useRouter } from "next/router";
import useUrlState, { Options } from "url-state-hook";
function useNextjsUrlState<T>(
key: string,
defaultValue: T,
options?: Omit<Options<T>, "useCurrentUrlHook" | "updateUrlFn">
) {
const { route, pathname } = useRouter();
const opts: Options<T> = {
...options,
useCurrentUrlHook: () => {
const { asPath } = useRouter();
return asPath;
},
updateUrlFn: (searchString: string) => {
typeof window === "undefined"
? () => {}
: Router.replace(route, `${pathname}${searchString}`, {
shallow: true
});
}
};
return useUrlState(key, defaultValue, opts);
}
export default useNextjsUrlState;
example.tsx
import React from "react";
import useNextjsUrlState from "./use-next-js-url-state";
const Example: FC = () => {
const [value, setValue] = useNextjsUrlState("s", "default value");
return (
<div>
<input value={value} onChange={e => setValue(e.target.value)} />
</div>
);
};
Api
Hook Parameters
param | description | required? |
---|---|---|
key | url query-param name used when storing the state in the url | yes |
defaultValue | default state value used when a initial value cannot be taken from the current url | yes |
options | Options object | no |
Options
key | description | default value |
---|---|---|
decode | function that deserializes the value stored in the url. Out of the box this hook will work with strings and numbers, but if a object or array is used as the state value, you need to supply a function to deserialize a string into the expected type | |
useCurrentUrlHook | a function or React hook that returns the current url | ReactRouterDom.useLocation() |
updateUrlFn | a function that can be used to update the current url | ReactRouterDom.useHistory().replace |
urlUpdateDebouce | a time in MS to debounce the updating of the url, this is necessary to prevent race conditions where multiple useUrlState() hooks update their state at the same time | 500 |
License
MIT © williammetcalf
This hook is created using create-react-hook.