如何将 dom 操作脚本包含到 SSR Next.js 应用程序中

Edg*_*oro 5 node.js webpack-dev-server next.js

我遇到以下错误:

Warning: Text content did not match. Server: "But I want to be altered by the client" Client: "Test"
    in div (at pages/index.tsx:17)
    in div (at pages/index.tsx:6)
    in HomePage (at _app.tsx:5)
    in MyApp
    in Container (created by AppContainer)
    in AppContainer
Run Code Online (Sandbox Code Playgroud)

...使用以下设置:

NextJS 应用组件:

function HomePage() {
  return (
    <>
      <div id="test-div">I am rendered on the server.</div>
      <script src="http://localhost:8080/bundle.js"></script>
    </>
  );
}

export default HomePage;
Run Code Online (Sandbox Code Playgroud)

(注意:该 URLhttp://localhost:8080/bundle.js假设 webpack-dev-server 正在运行并提供该资源)

包含的“示例”脚本:

const element = document.getElementById('test-div') as any;
element.innerHTML = 'But I want to be altered by the client';
Run Code Online (Sandbox Code Playgroud)

在一个简单的设置中,我只有一个静态 html 文件,声明一个 div 元素并包含“示例”脚本。

但我想使用 NextJS,因为我想将动态 (SSR) 内容呈现到页面中(例如来自 cms 的文本内容)。

我注意到,有时(如果脚本执行需要更多毫秒的时间),没有错误。只需在示例脚本中做一些耗时的事情。

另一种hacky 方法是setTimeout在示例脚本中使用。在我知道为什么会发生这种情况之前,我不想这样做:

setTimeout(function() {
  const element = document.getElementById('test-div') as any;
  element.innerHTML = 'But I want to be altered by the client';
}, 20);

Run Code Online (Sandbox Code Playgroud)

Nik*_*lev 13

Next.js 11.0.0 及以上

您可以使用Next.js Script 组件来加载第三方脚本。

// pages/index.js
import Script from 'next/script'

function Home() {
  return (
    <>
      <Script src="https://www.google-analytics.com/analytics.js" />
    </>
  )
}
Run Code Online (Sandbox Code Playgroud)

使用next/script,您可以定义strategy属性,Next.js 将优化脚本的加载。

Next.js 11.0.0 之前

浏览器和document,window对象在服务器端渲染期间不可用。

您可以在 React 组件挂载后初始化操作 DOM 的脚本。

useEffect(() => init(), [])
Run Code Online (Sandbox Code Playgroud)

要添加外部脚本,您可以执行以下操作:

useEffect(() => require('../babylon.js'), [])
Run Code Online (Sandbox Code Playgroud)

要包含来自另一台服务器的脚本,您可以添加一个script标签:

useEffect(() => {
  const script = document.createElement("script");
  script.src = "http://localhost:8080/bundle.js";
  script.async = true;
  document.body.appendChild(script);
},[])
Run Code Online (Sandbox Code Playgroud)

如果您要添加 DOM 侦听器,则还需要进行清理。

使用效果挂钩

清理效果