This is basically the root of the page. And it has 3 components, the MainMap (Client) the ListCasas(Server).
The button at the end changes the url searchParams and updates the UI. Now, this code runs as expected (UI wise) but in the console there are a ton of errors, due to it being a client component, as ListCasas was supposed to be Server.
I think this might also be causing page reloads. But it seems that the error fundamentally comes down to the useMediaQuery(). It requires a client component to not throw a error (useEffect, useState) And so I can’t figure out a way to be able to keep this a server component, but also know the window size?
code for mapClientComponent.tsx
'use client';
import MainMap from '@/app/[lang]/components/main-map';
import ListCasas from '../../ui/list-casas';
import NavBar from '../components/nav';
import { Locale } from '@/i18next.config';
import { getDictionary } from '@/app/lib/dictionary';
import { getImoveis } from '@/app/lib/data';
import { Suspense, useState } from 'react';
import FiltersBar from './bar';
import { usePathname, useSearchParams } from 'next/navigation';
import { useRouter } from 'next/navigation';
import useMediaQuery from '@/hooks/mediaQuery';
// import dynamic from 'next/dynamic';
// const useMediaQuery = dynamic(() => import('@/hooks/mediaQuery'), {
// ssr: false,
// });
export default function MapClientComponent({
params,
searchParams,
mapData,
page,
}: {
params: { lang: Locale };
mapData: any;
page: any;
searchParams?: {
// query?: string;
lat?: string;
lng?: string;
zona?: string;
page?: string;
sorting?: string;
types?: string;
min_price?: string;
max_price?: string;
number_of_rooms?: string;
exact_matches?: string;
yt?: string;
vr?: string;
beach?: string;
pool?: string;
isMapVisible?: string;
};
}) {
const lg = useMediaQuery(1024);
const isVis = searchParams?.isMapVisible || 'false';
const isMapVisible = isVis === 'true'; // Convert to boolean
const mapShouldShow = lg ? isMapVisible : true;
const listShouldShow = lg ? !isMapVisible : true;
// console.log('lg', lg);
// console.log(isMapVisible, 'isvisible');
// console.log(mapShouldShow, 'mapShouldShow');
// console.log(listShouldShow, 'listShouldShow');
//logic for visibility button
const searchParamss = useSearchParams();
const pathName = usePathname();
const { replace } = useRouter();
const paramss = new URLSearchParams(searchParamss);
function handleVis() {
const newIsMapVisible =
searchParams?.isMapVisible === 'true' ? 'false' : 'true';
paramss.set('isMapVisible', newIsMapVisible.toString());
replace(`${pathName}?${paramss.toString()}`);
}
return (
<div className="flex h-[100vh] min-w-full pt-[120px]">
{mapShouldShow && (
<Suspense
key={isMapVisible.toString() + lg.toString()}
fallback={'map loading...'}
>
<MainMap
isMapVisible={isMapVisible}
houses={mapData.houses}
dictionary={page}
lang={params.lang}
defaultCenter={{ lat: searchParams?.lat, lng: searchParams?.lng }}
/>
</Suspense>
)}
{listShouldShow && (
<Suspense key={'listCasas'} fallback={'List loading...'}>
<ListCasas
params={{ lang: params.lang }}
searchParams={{
sorting: searchParams?.sorting,
page: searchParams?.page,
zona: searchParams?.zona,
tipos: searchParams?.types,
min_price: searchParams?.min_price,
max_price: searchParams?.max_price,
number_of_rooms: searchParams?.number_of_rooms,
exact_matches: searchParams?.exact_matches,
yt: searchParams?.yt,
vr: searchParams?.vr,
beach: searchParams?.beach,
pool: searchParams?.pool,
}}
/>
</Suspense>
)}
<button
className="absolute inset-x-0 bottom-6 flex justify-center text-center text-white"
onClick={() => handleVis()}
>
<div className="w-[150px] bg-black p-2">
{searchParams?.isMapVisible === 'true' ? 'Show List' : 'Show Map'}
</div>
</button>
</div>
);
}
code for mediaQuery.ts:
import { useState, useEffect } from 'react';
const useMediaQuery = (width: number) => {
const [targetReached, setTargetReached] = useState(false);
const updateTarget = (e: MediaQueryListEvent) => {
setTargetReached(e.matches);
};
useEffect(() => {
const media = window.matchMedia(`(max-width: ${width}px)`);
media.addEventListener('change', updateTarget);
// Check on mount (callback is not called until a change occurs)
if (media.matches) {
setTargetReached(true);
}
return () => media.removeEventListener('change', updateTarget);
}, [width]);
return targetReached;
};
export default useMediaQuery;
UI working as expected, but console throws errors:
CasaCard is a child to ListCasas…
app-index.js:33 Warning: async/await is not yet supported in Client Components, only Server Components. This error is often caused by accidentally adding 'use client' to a module that was originally written for the server. at ListCasas
app-index.js:33 Warning: A component was suspended by an uncached promise. Creating promises inside a Client Component or hook is not yet supported, except via a Suspense-compatible library or framework. at ListCasas
Warning: async/await is not yet supported in Client Components, only Server Components. This error is often caused by accidentally adding
‘use client’ to a module that was originally written for the server. at CasaCard
app-index.js:33 Warning: A component was suspended by an uncached promise. Creating promises inside a Client Component or hook is not yet supported, except via a Suspense-compatible library or framework. at CasaCard