我正在try 在Reaction上下文中存储有关客户端的一些基本(非敏感)用户信息,例如他们的显示名称和个人资料图片.信息存储在本地存储中,因此即使客户端关闭/重新加载页面,它也会保持不变,并且上下文从那里获取数据,并在客户端组件中显示数据.在功能上,它运行得很好.然而,我遇到了一些问题:

  1. 为了避免水化不匹配错误,我必须禁用整个组件的SSR.

  2. 即使我一直启用SSR,内容加水所需的时间也比其他客户端组件多得多,即使我开发了应用程序.这种布局变化真的让我很烦.

我的问题是,我如何才能立即显示这些信息?我还没有见过其他人遇到这个问题.如果我用错误的方式存储它,什么才是正确的方式?

我制造了minimum working example个虫子.我试着在nextjs中查找各种使用react上下文的方法,但似乎没有一种方法表明我做错了什么.我也试着对next-themes进行逆向工程,以弄清楚它是如何工作的,但我不能完全理解它.

如有任何帮助,将不胜感激!

更新

我试着想办法摆脱这种拖延,但无济于事.我普遍认为这只是使用SSR的结果,服务器呈现的页面甚至在客户端组件可以挂载之前就加载了(尽管在生产模式下这种时间差不那么明显).Next-Themes似乎避免这种情况的方法是简单地阻止页面显示,直到它检测到html标签和媒体查询.

作为解决方案,我实现了一个框架组件以避免布局移动.我仍然对解决方案持开放态度,以防有人知道如何立即加载这些信息,但我已经接受了这可能是不可能的.

推荐答案

您的问题似乎围绕着AuthContext组件及其与Next.js中的服务器端呈现的交互.

出现问题的原因是,服务器和客户端之间的userData值不同,从而导致水合失败.出现此故障的原因是,React API hydrateRoot()希望呈现的内容与服务器呈现的HTML匹配.

你可以参考React documentation和中间的"trap "部分了解更多细节.建议避免在呈现逻辑中直接使用typeof window !== 'undefined'之类的判断或访问localStorage之类的纯浏览器API,因为这可能会导致服务器和客户端快照之间不匹配.

以下是我的解决方法:

  1. 使用默认值null初始化useState挂钩,以确保一致的初始渲染.
  2. 安装组件后,使用useEffect挂钩更新userData.
  3. go 掉动态进口,直接进口ClientComponent个.
  4. 更新前在客户端组件中显示某些内容

以下是修改后的AuthContext组件:

import React, { createContext, useContext, useEffect, useState, Dispatch, SetStateAction } from "react";

export default function AuthContext({
  children,
}: {
  children: React.ReactNode;
}) {
  const [user, setUser] = useState<string | null>(null); // Initialize with null
  
  // update after component mount
  useEffect(() => {
    const userData = getUser();
    if(userData){
      setUser(userData);
    }
  }, []);

  return (
    <Context.Provider value={{ userData: user, setUserData: setUser }}>
      {children}
    </Context.Provider>
  );
}

export const useAuthContext = () => useContext(Context);

const getUser = () => {
  if(typeof window === 'undefined') return null; // Check for server-side rendering
  let user;
  try {
    user = localStorage.getItem("user");
    if (!user) {
      user = "I want this to be rendered instantly too!";
      localStorage.setItem("user", user);
      return user;
    }
  } catch (e) {}
  return user;
};

请注意,这种方法可能会使水化速度变慢,因为组件必须渲染两次.在慢速连接上中断用户体验.JavaScript代码的加载时间可能比初始HTML呈现时间晚得多,因此在水合之后立即呈现不同的UI也可能会让用户感到discord.

但同样,您不应该在呈现逻辑中访问仅限浏览器的API. 希望这对你有用.

Typescript相关问答推荐

具有映射返回类型的通用设置实用程序

对数组或REST参数中的多个函数的S参数进行类型判断

Next.js错误:不变:页面未生成

编剧错误:正在等待Expect(Locator).toBeVisible()

通配符路径与每条路径一起显示

适当限制泛型函数中的记录

迭代通过具有泛型值的映射类型记录

有什么方法可以类型安全地包装import()函数吗?

TYPE FOR ARRAY,其中每个泛型元素是单独的键类型对,然后在该数组上循环

基于泛型的条件接口键

自定义 Select 组件的类型问题:使用带逗号的泛型类型<;T与不带逗号的<;T&>;时出错

如何在脚本中输入具有不同数量的泛型类型变量的函数?

17个Angular 的延迟观察.如何在模板中转义@符号?

界面中数组中的混合类型导致打字错误

将超类型断言为类型脚本中的泛型参数

使用RXJS获取数据的3种不同REST API

窄SomeType与SomeType[]

TS2532:对象可能未定义

在Nestjs中,向模块提供抽象类无法正常工作

从接口推断模板参数?