useTitle.js
1 import { useLayoutEffect } from 'preact/hooks'; 2 import { matchPath } from 'react-router-dom'; 3 import { subscribeKey } from 'valtio/utils'; 4 5 import states from './states'; 6 7 const { VITE_CLIENT_NAME: CLIENT_NAME } = import.meta.env; 8 9 export default function useTitle(title, path) { 10 function setTitle() { 11 const { currentLocation } = states; 12 const hasPaths = Array.isArray(path); 13 let paths = hasPaths ? path : []; 14 // Workaround for matchPath not working for optional path segments 15 // https://github.com/remix-run/react-router/discussions/9862 16 if (!hasPaths && /:?\w+\?/.test(path)) { 17 paths.push(path.replace(/(:\w+)\?/g, '$1')); 18 paths.push(path.replace(/\/?:\w+\?/g, '')); 19 } 20 let matched = false; 21 if (paths.length) { 22 matched = paths.some((p) => matchPath(p, currentLocation)); 23 } else if (path) { 24 matched = matchPath(path, currentLocation); 25 } 26 console.debug('setTitle', { title, path, currentLocation, paths, matched }); 27 if (matched) { 28 document.title = title ? `${title} / ${CLIENT_NAME}` : CLIENT_NAME; 29 } 30 } 31 32 useLayoutEffect(() => { 33 const unsub = subscribeKey(states, 'currentLocation', setTitle); 34 setTitle(); 35 return unsub; 36 }, [title, path]); 37 }