Reactjs React Next.js-关于SSR模式的三个相关问题

Reactjs React Next.js-关于SSR模式的三个相关问题,reactjs,next.js,server-side-rendering,Reactjs,Next.js,Server Side Rendering,下面的问题是关于如何使用next.js和react来实现相互叠加的SSR构建,所以我想我会将其写在一篇文章中。我的主要问题是第三个问题,但我觉得我需要先理解前两个问题才能达到目的。现在我们开始: 一,。在客户端收到整个页面后,总是从头开始重新执行该页面,这对吗 考虑下面这个next.js页面组件: const Page = () => { const [state, setState] = useState(getState()); function getState() {

下面的问题是关于如何使用next.js和react来实现相互叠加的SSR构建,所以我想我会将其写在一篇文章中。我的主要问题是第三个问题,但我觉得我需要先理解前两个问题才能达到目的。现在我们开始:

一,。在客户端收到整个页面后,总是从头开始重新执行该页面,这对吗

考虑下面这个next.js页面组件:

const Page = () => {
  const [state, setState] = useState(getState());

  function getState() {
    console.log("compute initial state");
    return 1;
  }

  return <>{state}</>;
};

现在,从SSR的角度来看,有了这种模式,应用程序就可以了。但我要介绍的是客户端需要做的额外工作:即使在第一次渲染时定义了
window
,它也只能在第二次渲染时使用

对于这个较小的示例,这并没有起到很大的作用,但在一个较大的应用程序中,可能会出现闪烁,因为不必要的第一次渲染会在几毫秒后更新。此外,代码变得更难阅读,更容易出错

这里我想要的解决方案与上面的第一个问题有关:我是否可以避免应用程序从头开始,而是直接从第二个渲染开始?是否有某种模式是我迄今为止一直忽略的

注意:当然,我可以重写组件,只需检查是否定义了
window

  return (
    <>
      <h1>{window ? window.innerWidth : "value pending ..."}</h1>
    </>
  );
返回(
{window?window.innerWidth:“值挂起…”
);
但是,这将导致react警告,并导致我在上面喜欢的文章中描述的其他问题。还可以看到

React期望服务器和客户端之间呈现的内容相同。它可以修补文本内容中的差异,但您应该将不匹配视为bug并加以修复


非常感谢你的帮助

在客户端收到整个页面后,总是从头开始重新执行该页面,这是对的吗?

是和否。初始html构建在服务器上,并以html的形式发送到客户端,然后对react进行水合处理,以使您的页面变得具有交互性。作为一个例子,考虑这个“页面”:

导出默认函数MyPage(){
const[greeting,setGreeting]=React.useState(“Hello”)
React.useffect(()=>{
问候语(“再见”)
}, [])
返回({greeting}

) }
当页面在服务器上呈现时,它将呈现为html并将该html发送到客户端。因此,如果您检查页面的源代码,您将看到:

你好

然后,在客户端上,react被水合并运行
useEffect
,因此在浏览器中,您会看到一个带有“再见”字样的段落

无论您使用的是SSR(html是在服务器上按需创建的)还是SSG(html是在构建时创建到静态html页面中的),都是如此

如果预呈现的文档将被立即丢弃,那么它对客户端有什么价值?

如果你明白我的第一点,整个文件不会被扔掉。SSR中的值是,如果您希望初始问候语文本不是“Hello”。例如,如果您希望服务器解析身份验证令牌,获取用户配置文件,并在页面加载时使用“Hello Jim”为
问候语
添加种子,那么您更喜欢SSR。如果在将html发送到客户端之前没有任何服务器端处理,可以选择SSG

考虑这两个“页面”:

//使用SSR
导出默认函数MyPage({customerName}){
返回({customerName}

) }
//使用SSG
导出默认函数MyPage({customerName}){
const[greeting,setGreeting]=React.useState(“Hello”)
React.useffect(()=>{
//呼叫服务器以获取客户的姓名
const name=myApi.get('/name')
setGreeting(`Hello${name}`)
}, [])
返回({greeting}

) }
在第一个示例中,服务器呈现带有客户名称的
p
标记(来自服务器上的某个进程),因此html源代码将包括该客户的名称。这里没有扔东西

在第二个示例中,站点构建为html,源代码的
p
标记显示“Hello”。访问页面时,
useffect
运行,api响应时,
p
标记更新。因此,用户将在x微秒内看到“Hello”,然后切换到“Hello Jim”

这是否意味着我不必要地必须在客户端“双重渲染”某些组件?

否-您可以控制在服务器上渲染的内容,而不是在客户机上渲染的内容。如果您在服务器上为组件添加了数据种子,但没有在客户端对其进行更改,则不会重新加载

在您的示例中,是的-您是双重渲染。但你可能不需要这样做。正如您所指出的,
窗口
在客户端上不存在。如果在获得窗口大小之前必须向用户显示“value pending…”行,那么您将执行双重呈现—一次在服务器上填充该字符串,然后在客户端上替换该字符串

如果您不需要显示挂起的行,只需要在
窗口实际存在时在客户端上显示值,您可以这样重写它:

导出默认功能页(){
const[value,setValue]=React.useState();
React.useffect(()=>{
const newValue=window.innerWidth;//依赖于窗口的某些计算或订阅
设置值(新值)
}, []);
如果(值){
返回{value}
}
返回空
};
在这种情况下,服务器上不会呈现任何内容,因为服务器上没有
值。只有当客户端水合后,
useffect
才会运行、更新
value
,并一次性渲染组件

  return (
    <>
      <h1>{window ? window.innerWidth : "value pending ..."}</h1>
    </>
  );