1- import React , { useEffect } from 'react' ;
1+ import React , { useEffect , useLayoutEffect } from 'react' ;
22import { useMatches , useLocation } from 'react-router-dom' ;
33import { Cssville } from "cssville-generators/build/cssville" ;
44
@@ -13,62 +13,74 @@ export const PageMetadata: React.FC<MetadataProps> = ({
1313} ) => {
1414 const matches = useMatches ( ) ;
1515 const location = useLocation ( ) ;
16-
17- useEffect ( ( ) => {
18- // Get the last match which contains the current route's handle
16+
17+ // Function to get metadata from current route
18+ const getMetadata = ( ) => {
1919 const match = matches [ matches . length - 1 ] ;
2020 let title = defaultTitle ;
2121 let description = defaultDescription ;
22-
23- // Extract metadata from the route's handle
22+
2423 if ( match && match . handle ) {
2524 const handle = match . handle as any ;
26-
27- // For CSS Classes pages, we need to handle the dynamic title
25+
2826 if ( handle . category === "CSS Classes" && handle . title === "" ) {
2927 const parts = location . pathname . split ( "/" ) ;
3028 const className = parts [ parts . length - 1 ] ;
3129 const generator = Cssville . generators . find ( g => g . name === className ) ;
32-
30+
3331 if ( generator ) {
3432 title = `${ generator . name } - Cssville CSS Classes` ;
3533 description = `Learn about Cssville's ${ generator . name } utility classes.` ;
3634 }
3735 } else if ( handle . title ) {
38- // For other pages, use the title from the handle
3936 title = handle . title ;
4037 if ( handle . category !== "Home" ) {
4138 title += " - Cssville" ;
4239 }
43-
40+
4441 if ( handle . description ) {
4542 description = handle . description ;
4643 }
4744 }
4845 }
49-
46+
47+ return { title, description } ;
48+ } ;
49+
50+ // Update metadata immediately during render
51+ const { title, description } = getMetadata ( ) ;
52+
53+ // Synchronously update the title as soon as possible
54+ if ( typeof document !== 'undefined' ) {
55+ document . title = title ;
56+ }
57+
58+ // Use useLayoutEffect for DOM mutations before browser paint
59+ useLayoutEffect ( ( ) => {
60+ const { title, description } = getMetadata ( ) ;
61+
5062 // Update document head
5163 document . title = title ;
52-
64+
5365 // Update meta description
5466 let metaDescription = document . querySelector ( 'meta[name="description"]' ) ;
5567 if ( metaDescription ) {
5668 metaDescription . setAttribute ( 'content' , description ) ;
5769 }
58-
70+
5971 // Update Open Graph and Twitter meta tags
6072 const ogTitle = document . querySelector ( 'meta[property="og:title"]' ) ;
6173 const ogDescription = document . querySelector ( 'meta[property="og:description"]' ) ;
6274 const twitterTitle = document . querySelector ( 'meta[name="twitter:title"]' ) ;
6375 const twitterDescription = document . querySelector ( 'meta[name="twitter:description"]' ) ;
64-
76+
6577 if ( ogTitle ) ogTitle . setAttribute ( 'content' , title ) ;
6678 if ( ogDescription ) ogDescription . setAttribute ( 'content' , description ) ;
6779 if ( twitterTitle ) twitterTitle . setAttribute ( 'content' , title ) ;
6880 if ( twitterDescription ) twitterDescription . setAttribute ( 'content' , description ) ;
69-
81+
7082 } , [ matches , location . pathname , defaultTitle , defaultDescription ] ) ;
71-
83+
7284 // This component doesn't render anything
7385 return null ;
74- } ;
86+ } ;
0 commit comments