snippetjavascriptTip
React useHash and useSearchParam hooks
Viewed 0 times
hooksandreactusehashusesearchparam
Problem
If you want to track the browser's location hash value or search params in React, you can create a couple of custom hooks to handle this. While seemingly simple, listening for changes in these values can be a little tricky, but also quite useful.
Tracking the browser's location hash value is the easier of the two tasks. All you need to do is create a custom hook that uses the
You can then use the
For the search params, the process is similar but a little more involved. You can create a custom hook that uses the
Then, use the
Tracking the browser's location hash value is the easier of the two tasks. All you need to do is create a custom hook that uses the
useState() hook to lazily get the hash property of the Location object.You can then use the
useCallback() hook to create a handler that updates the state. Finally, use the useEffect() hook to add a listener for the 'hashchange' event when mounting and clean it up when unmounting.For the search params, the process is similar but a little more involved. You can create a custom hook that uses the
useState() hook to lazily get the value of a specific search param using the URLSearchParams() constructor.Then, use the
useCallback() hook to create a handler that updates the state. Finally, use the useEffect() hook to add listeners for the 'popstate', 'pushstate', and 'replacestate' events when mounting and clean them up when unmounting.Solution
const useHash = () => {
const [hash, setHash] = React.useState(() => window.location.hash);
const hashChangeHandler = React.useCallback(() => {
setHash(window.location.hash);
}, []);
React.useEffect(() => {
window.addEventListener('hashchange', hashChangeHandler);
return () => {
window.removeEventListener('hashchange', hashChangeHandler);
};
}, []);
const updateHash = React.useCallback(
newHash => {
if (newHash !== hash) window.location.hash = newHash;
},
[hash]
);
return [hash, updateHash];
};
const MyApp = () => {
const [hash, setHash] = useHash();
React.useEffect(() => {
setHash('#list');
}, []);
return (
<>
<p>window.location.href: {window.location.href}</p>
<p>Edit hash: </p>
<input value={hash} onChange={e => setHash(e.target.value)} />
</>
);
};
ReactDOM.createRoot(document.getElementById('root')).render(
<MyApp />
);You can then use the
useCallback() hook to create a handler that updates the state. Finally, use the useEffect() hook to add a listener for the 'hashchange' event when mounting and clean it up when unmounting.For the search params, the process is similar but a little more involved. You can create a custom hook that uses the
useState() hook to lazily get the value of a specific search param using the URLSearchParams() constructor.Then, use the
useCallback() hook to create a handler that updates the state. Finally, use the useEffect() hook to add listeners for the 'popstate', 'pushstate', and 'replacestate' events when mounting and clean them up when unmounting.Code Snippets
const useHash = () => {
const [hash, setHash] = React.useState(() => window.location.hash);
const hashChangeHandler = React.useCallback(() => {
setHash(window.location.hash);
}, []);
React.useEffect(() => {
window.addEventListener('hashchange', hashChangeHandler);
return () => {
window.removeEventListener('hashchange', hashChangeHandler);
};
}, []);
const updateHash = React.useCallback(
newHash => {
if (newHash !== hash) window.location.hash = newHash;
},
[hash]
);
return [hash, updateHash];
};
const MyApp = () => {
const [hash, setHash] = useHash();
React.useEffect(() => {
setHash('#list');
}, []);
return (
<>
<p>window.location.href: {window.location.href}</p>
<p>Edit hash: </p>
<input value={hash} onChange={e => setHash(e.target.value)} />
</>
);
};
ReactDOM.createRoot(document.getElementById('root')).render(
<MyApp />
);const useSearchParam = param => {
const getValue = React.useCallback(
() => new URLSearchParams(window.location.search).get(param),
[param]
);
const [value, setValue] = React.useState(getValue);
React.useEffect(() => {
const onChange = () => {
setValue(getValue());
};
window.addEventListener('popstate', onChange);
window.addEventListener('pushstate', onChange);
window.addEventListener('replacestate', onChange);
return () => {
window.removeEventListener('popstate', onChange);
window.removeEventListener('pushstate', onChange);
window.removeEventListener('replacestate', onChange);
};
}, []);
return value;
};
const MyApp = () => {
const post = useSearchParam('post');
return (
<>
<p>Post param value: {post || 'null'}</p>
<button
onClick={() =>
history.pushState({}, '', location.pathname + '?post=42')
}
>
View post 42
</button>
<button onClick={() => history.pushState({}, '', location.pathname)}>
Exit
</button>
</>
);
};
ReactDOM.createRoot(document.getElementById('root')).render(
<MyApp />
);Context
From 30-seconds-of-code: use-hash-search-param
Revisions (0)
No revisions yet.