@@ -47,12 +47,18 @@ export const FeedList = ({
47
47
const isSmartData = dataFeedType === "smartdata"
48
48
const isUSGovernmentMacroeconomicData = dataFeedType === "usGovernmentMacroeconomicData"
49
49
50
- // Get network directly from URL
51
- const networkFromURL =
52
- typeof window !== "undefined" ? new URLSearchParams ( window . location . search ) . get ( "network" ) : null
50
+ // Get network directly from URL with better SSR handling
51
+ const getInitialNetwork = ( ) => {
52
+ if ( typeof window === "undefined" ) return initialNetwork
53
+ const params = new URLSearchParams ( window . location . search )
54
+ const networkParam = params . get ( "network" )
55
+ return networkParam || initialNetwork
56
+ }
57
+
58
+ const networkFromURL = getInitialNetwork ( )
53
59
54
60
// If URL has a network param, use it directly
55
- const effectiveInitialNetwork = networkFromURL || initialNetwork
61
+ const effectiveInitialNetwork = networkFromURL
56
62
57
63
// Initialize state with the URL value
58
64
const [ currentNetwork , setCurrentNetwork ] = useState ( effectiveInitialNetwork )
@@ -87,27 +93,46 @@ export const FeedList = ({
87
93
}
88
94
} , [ currentNetwork , isStreams ] )
89
95
90
- // Force initial sync with URL
96
+ // Force initial sync with URL - handle hydration mismatches
91
97
useEffect ( ( ) => {
92
- // Get the latest network from URL
93
- const latestNetworkFromURL = getNetworkFromURL ( )
94
- if ( latestNetworkFromURL !== currentNetwork ) {
95
- setCurrentNetwork ( latestNetworkFromURL )
98
+ // Only run this effect on the client side after mount
99
+ if ( typeof window !== "undefined" ) {
100
+ const latestNetworkFromURL = getNetworkFromURL ( )
101
+ if ( latestNetworkFromURL !== currentNetwork ) {
102
+ setCurrentNetwork ( latestNetworkFromURL )
103
+ }
96
104
}
105
+ } , [ ] ) // Run only once on mount
97
106
98
- // Force a redraw after a short delay
107
+ // Additional sync for when window loads (fallback)
108
+ useEffect ( ( ) => {
99
109
if ( typeof window !== "undefined" ) {
100
- // execute after the DOM is fully loaded
101
- window . addEventListener ( "load" , ( ) => {
110
+ const handleLoad = ( ) => {
102
111
const networkFromURL = getNetworkFromURL ( )
103
- setCurrentNetwork ( networkFromURL )
104
- // Note: network button updates removed since we now use dropdown selector
105
- } )
112
+ if ( networkFromURL !== currentNetwork ) {
113
+ setCurrentNetwork ( networkFromURL )
114
+ }
115
+ }
116
+
117
+ // If window is already loaded, run immediately
118
+ if ( document . readyState === 'complete' ) {
119
+ handleLoad ( )
120
+ } else {
121
+ window . addEventListener ( "load" , handleLoad )
122
+ return ( ) => window . removeEventListener ( "load" , handleLoad )
123
+ }
106
124
}
107
125
} , [ ] )
108
126
109
127
// Track the selected network type (mainnet/testnet)
110
128
const [ selectedNetworkType , setSelectedNetworkType ] = useState < "mainnet" | "testnet" > ( "mainnet" )
129
+
130
+ // Track hydration to prevent SSR mismatch
131
+ const [ isHydrated , setIsHydrated ] = useState ( false )
132
+
133
+ useEffect ( ( ) => {
134
+ setIsHydrated ( true )
135
+ } , [ ] )
111
136
112
137
// Regular query string states
113
138
const [ searchValue , setSearchValue ] = useQueryString ( "search" , "" )
@@ -163,7 +188,32 @@ export const FeedList = ({
163
188
]
164
189
const [ streamsChain ] = useState ( initialNetwork )
165
190
const activeChain = isStreams ? streamsChain : currentNetwork
166
- const chain = chains . find ( ( c ) => c . page === activeChain ) || chains [ 0 ]
191
+
192
+ // More robust chain finding - ensure we have a valid chain
193
+ const chain = useMemo ( ( ) => {
194
+ // During SSR, if we don't have an activeChain but we have a network param in the URL,
195
+ // try to find the chain directly from the URL param to prevent hydration mismatch
196
+ if ( ! activeChain ) {
197
+ // Check if we have a network param that we can use directly
198
+ if ( typeof window !== "undefined" ) {
199
+ const urlParams = new URLSearchParams ( window . location . search )
200
+ const networkParam = urlParams . get ( "network" )
201
+ if ( networkParam ) {
202
+ const foundFromUrl = chains . find ( ( c ) => c . page === networkParam )
203
+ if ( foundFromUrl ) {
204
+ return foundFromUrl
205
+ }
206
+ }
207
+ }
208
+ return chains [ 0 ] // fallback only if no activeChain
209
+ }
210
+
211
+ const foundChain = chains . find ( ( c ) => c . page === activeChain )
212
+ if ( ! foundChain ) {
213
+ return chains [ 0 ]
214
+ }
215
+ return foundChain
216
+ } , [ activeChain , chains ] )
167
217
const chainMetadata = useGetChainMetadata ( chain , initialCache && initialCache [ chain . page ] )
168
218
const wrapperRef = useRef ( null )
169
219
@@ -644,16 +694,19 @@ export const FeedList = ({
644
694
flexWrap : "nowrap"
645
695
} }
646
696
>
647
- < ChainSelector
648
- chains = { chains }
649
- selectedChain = { chain }
650
- currentNetwork = { currentNetwork }
651
- onChainSelect = { handleNetworkSelect }
652
- onNetworkTypeChange = { handleNetworkTypeChange }
653
- dataFeedType = { dataFeedType }
654
- availableNetworkTypes = { availableNetworkTypes }
655
- selectedNetworkType = { selectedNetworkType }
656
- />
697
+ { isHydrated && (
698
+ < ChainSelector
699
+ key = { `chain-selector-${ chain . page } ` } // Force re-render when chain changes
700
+ chains = { chains }
701
+ selectedChain = { chain }
702
+ currentNetwork = { currentNetwork }
703
+ onChainSelect = { handleNetworkSelect }
704
+ onNetworkTypeChange = { handleNetworkTypeChange }
705
+ dataFeedType = { dataFeedType }
706
+ availableNetworkTypes = { availableNetworkTypes }
707
+ selectedNetworkType = { selectedNetworkType }
708
+ />
709
+ ) }
657
710
</ div >
658
711
</ >
659
712
) }
0 commit comments