I am writing a simple React CRUD app, using NextJS 13 and its app router.
I have a route, in which page.tsx
is a client component.
page.tsx
'use client'
import DataGrid from './DataGrid'
const List = (props) => (
<DataGrid>...</DataGrid>
)
export default List
DataGrid.tsx
'use client'
const DataGrid = ({entity, identifier}) => {
const gridIdentifier = `${window.location.pathname}-${entity}`;
const gridSettings = JSON.parse(localStorage.getItem(gridIdentifier) || '{}');
return ...
}
export default DataGrid
And when I try to hit my route, the console shows
✓ Compiled in 1638ms (12671 modules)
X src/common/components/DataGrid/DataGrid.tsx (55:26) @ DataGrid
X ReferenceError: window is not defined
at DataGrid (./src/common/components/DataGrid/DataGrid.tsx:40:28)
53 | const router = useRouter();
54 | const ModalFormComponent = modalFormComponent as React.ElementType;
> 55 | const gridIdentifier = `${window.location.pathname}-${entity}`;
| ^
56 | const gridSettings = JSON.parse(localStorage.getItem(gridIdentifier) || '{}');
57 |
✓ Compiled /not-found in 758ms (12676 modules)
Isn’t the use client
directive supposed to allow the usage of browser APIs ?
I shouldn’t have to use useEffect
like it was the case before NextJS 13.
I tried to add the conventional check if (typeof window === 'undefined')
, but ended up with localStorage
being undefined as well.
I also tried to transform the List
parent into a server component, and having all its dependent components being client components whenever necessary, but it ended up being cubersome and useless.
2
Answers
I believe "use client" still renders your component once on the server before rendering again on the client. Using the client-only npm package, dynamically importing your client component, or wrapping in a useEffect should do the trick. Here’s the next docs where they talk about client component rendering: https://nextjs.org/docs/app/building-your-application/rendering/client-components and here’s where they talk about the client-only package https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#keeping-server-only-code-out-of-the-client-environment
or
or
yes,same problem found a very simple and useful solution is wrap your code of window by useEffect hook,such as: