我正在使用 NextJS 13 及其应用程序路由器编写一个简单的 React CRUD 应用程序。
我有一条路线,其中
page.tsx
是客户端组件。
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
当我尝试按路线行驶时,控制台会显示
✓ 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)
use client
指令不是应该允许使用浏览器API吗?
我不应该像 NextJS 13 之前那样使用 useEffect
。
我尝试添加常规检查
if (typeof window === 'undefined')
,但最终 localStorage
也未定义。
我还尝试将
List
父级转换为服务器组件,并在必要时将其所有依赖组件都作为客户端组件,但最终变得臃肿且无用。
我相信“使用客户端”仍然会在服务器上渲染您的组件一次,然后再在客户端上再次渲染。使用仅限客户端的 npm 包、动态导入客户端组件或包装在 useEffect 中应该可以解决问题。这是他们谈论客户端组件渲染的下一个文档:https://nextjs.org/docs/app/building-your-application/rendering/client-components,这里是他们谈论仅限客户端的包https ://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#keeping-server-only-code-out-of-the-client-environment
'use client'
import 'client-only'
const DataGrid = ({entity, identifier}) => {
...
}
或
const DataGrid = dynamic(() => import("./DataGrid"), { ssr: false });
const List = (props) => (
<DataGrid>...</DataGrid>
)
或
useEffect(() => {
const gridIdentifier = `${window.location.pathname}-${entity}`;
const gridSettings = JSON.parse(localStorage.getItem(gridIdentifier) || '{}');
}, []}