15

nextjs 如何不显示next_data的数据

 2 years ago
source link: https://www.xiabingbao.com/post/nextjs/nextjs-no-data-r7k70u.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
nextjs为了实现前段后的同构,会将渲染页面前的数据传给前端,那么如何不展示这些数据呢?

nextjs 提供了 getServerSideProps 方法(之前叫 getInitialProps 方法),用于在渲染页面之前请求数据,但 nextjs 框架为了能够前后端保持同步,会将请求到的数据,通过一个 script 标签传给前端:

<script id="__NEXT_DATA__" type="application/json"></script>

但有时候,我们并不想把一些原始数据暴露到前端页面中,如一些博客网站、新闻网站等,基本以展示数据为主,没有同构的需要。所以,如何隐藏掉__NEXT_DATA__中的数据,只展示构建好的 html 呢?

1. 使用方式

在 nextjs 的 GitHub 上,有一个 pull request: Allow disabling runtime JS in production for certain pages (experimental) #11949,讨论了这个功能。

[email protected]版本开始,为 pages 目录中的组件提供了一个unstable_runtimeJS的配置,当设置该参数为 false 后,则不会再展示__next_data__中的数据。

注意该设置只在process.env.NODE_ENV==='production'时生效。

不过,它带来的副作用也很大,它会导致整个页面实现的前端功能(如点击事件等)全部失效,包括该组件引用的子组件。

// pages/home.tsx

const Home = ({ nick, age }) => {
  const handleClick = () => {
    console.log('home click');
  };

  return (
    <div>
      <h1 onClick={handleClick}>home</h1>
      <p>{nick}</p>
      <p>{age}</p>
    </div>
  );
};

// 移除__next_data__,移除所有前端的js
export const config = {
  unstable_runtimeJS: false,
};

// https://www.nextjs.cn/docs/basic-features/pages#%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AB%AF%E6%B8%B2%E6%9F%93
export const getServerSideProps = async (context: any) => {
  const { nick, age } = await fetch('api');

  return { props: { nick, age } };
};

最终渲染出来的 html 结构:

remove-next-data-in-nextjs-蚊子的前端博客

2. 副作用

从上图中可以看到,unstable_runtimeJS副作用很少很大的,虽不再展示 getServerSideProps 方法中返回的数据,但整个页面所有的 script 标签也都没了。这就造成该组件和它所有的子组件,均没有了前端功能。

3. 解决方案

若真的想在前端加载 js,也是有办法的。那就是使用 script 标签,自己加载 js 链接或者内容。

3.1 外链的方式

假如我们把要加载的前端 js 放在了https://cdn.bootcdn.net/ajax/libs/axios/0.26.0/axios.js链接中,直接通过 script 标签的 src 引入即可:

const Home = ({ nick, age }) => {
  return (
    <div>
      <h1 onClick={handleClick}>home</h1>
      <p>{nick}</p>
      <p>{age}</p>
      <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.26.0/axios.js"></script>
    </div>
  );
};

3.2 内敛的方式

都是同一个项目的代码,单独把某一部分拿出去再构建,实在是不方便。这里可以把 js 代码转成字符串,写到 script 标签中。

3.2.1 dangerouslySetInnerHTML 属性

使用 script 标签的 dangerouslySetInnerHTML 属性:

<script
  dangerouslySetInnerHTML={{
    __html: `document.querySelector('h1')?.addEventListener('click', () => console.log(Date.now()));`,
  }}
></script>

3.2.2 script 标签的内容区

<script>{`document.querySelector('h1')?.addEventListener('click', () => console.log(Date.now()));`}</script>

3.2.3 利用 function 的 toString()

方法名调用 toString()会该方法的函数体,这里我们封装成一个立即执行函数的形式:

const Home = ({ nick, age }: any) => {
  // 所有前端要执行的js,放在这里面
  const bootstrap = () => {
    if (typeof document === 'undefined') {
      return;
    }
    document.querySelector('h1')?.addEventListener('click', () => console.log(Date.now()));
  };

  return (
    <div>
      <h1 onClick={handleClick}>home</h1>
      <p>{nick}</p>
      <p>{age}</p>
      <script dangerouslySetInnerHTML={{ __html: `(${bootstrap.toString()})()` }}></script>
    </div>
  );
};

最终编译后的效果:

function-tostring-蚊子的前端博客

从上面的分析也能看到,不是特别必要的时候,最好还是不要用unstable_runtimeJS禁用 js,否则为了实现相同的功能,就要用很多的奇技淫巧来弥补。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK