ReactHooks在SSR模式下常见问题及解决方案

服务端渲染(Server-Side Rendering),是指由服务侧完成页面的 HTML 结构拼接的页面处理技术。一般用于解决 SEO 问题和首屏加载速度问题。

由于 SSR 是在非浏览器环境执行 JS 代码,所以会出现很多问题。本文主要介绍 React Hooks 在 SSR 模式下常见问题及解决方案。

更多关于 SSR 的介绍可以看 UmiJS 的文档《服务端渲染(SSR)[1]》。

问题一:DOM/BOM 缺失

SSR 是在 node 环境下运行 React 代码,而此时 window、document、navigator 等全局属性没有。如果直接使用了这些属性,就会报错 window is not defined, document is not defined, navigator is not defined 等。

常见的错误用法是在 Hooks 执行过程中,直接使用了 document 等全局属性。

 
 
 
 
  1. import React, { useState } from 'react';
  2. export default () => {
  3.   const [state, setState] = useState(document.visibilityState);
  4.   return state;
  5. }

解决方案

1.将访问 DOM/BOM 的方法放在 useEffect/useLayoutEffect 中(服务端不会执行),避免服务端执行时报错,例如:

 
 
 
 
  1. import React, { useState, useEffect } from 'react';
  2. export default () => {
  3.   const [state, setState] = useState();
  4.   
  5.   useEffect(()=>{
  6.     setState(document.visibilityState);
  7.   }, []);
  8.   
  9.   return state;
  10. }

2.通过 isBrowser[2]来做环境判断

 
 
 
 
  1. import React, { useState } from 'react';
  2. function isBrowser() {
  3.   return !!(typeof window !== 'undefined' && window.document && window.document.createElement);
  4. }
  5. export default () => {
  6.   const [state, setState] = useState(isBrowser() && document.visibilityState);
  7.   
  8.   return state;
  9. }

问题二 useLayoutEffect Warning

如果使用了 useLayoutEffect,在 SSR 模式下,会出现以下警告

  • ️ Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format. This will lead to a mismatch between the initial, non-hydrated UI and the intended UI. To avoid this, useLayoutEffect should only be used in components that render exclusively on the client. See https://fb.me/react-uselayouteffect-SSR for common fixes.

解决方案

  1. 使用 useEffect 代替 useLayoutEffect(废话)
  2. 根据环境动态的指定是使用 useEffect 还是 useLayoutEffect。这是来自社区的一种 hack 解决方案,目前在react-redux[3]react-use[4]react-beautiful-dnd[5]均使用的这种方案。
 
 
 
 
  1. import { useLayoutEffect, useEffect } from 'react';
  2. const useIsomorphicLayoutEffect = isBrowser() ? useLayoutEffect : useEffect;
  3. export default useIsomorphicLayoutEffect;

总结:写 Hooks 时需要注意

1.不要在非 useEffect/useLayoutEffect 中,直接使用 DOM/BOM 属性

2.在非 useEffect/useLayoutEffect 使用 DOM/BOM 属性时,使用 isBrowser 判断是否在浏览器环境执行

3.如果某个 Hooks 需要接收 DOM/BOM 属性,需要支持函数形式传参。以 ahooks 的 useEventListener 举例,必须支持函数形式来指定 target 属性。

 
 
 
 
  1. import React, { useState } from 'react';
  2. import { useEventListener } from 'ahooks';
  3. export default () => {
  4.   const [value, setValue] = useState(0);
  5.   const clickHandler = () => {
  6.     setValue(value + 1);
  7.   };
  8.   useEventListener(
  9.     'click', 
  10.     clickHandler, 
  11.     { 
  12. -       target: document.getElemenetById('click-btn') 
  13. +       target: () => document.getElemenetById('click-btn') 
  14.     }
  15.   );
  16.   return (
  17.     
  18.       You click {value} times
  19.     
  20.   );
  21. };

4.使用 useIsomorphicLayoutEffect 来代替 useLayoutEffect

参考资料

  • fix: useDocumentVisiblility support SSR[6]
  • UmiJS 服务端渲染[7]
  • useLayoutEffect and SSR[8]

参考资料

[1]服务端渲染(SSR):

https://umijs.org/zh-CN/docs/SSR#服务端渲染(SSR)

[2]isBrowser:

https://github.com/alibaba/hooks/blob/master/packages/hooks/src/utils/canUseDom.ts

[3]react-redux:

https://github.com/reduxjs/react-redux/blob/d16262582b2eeb62c05313fca3eb59dc0b395955/src/components/connectAdvanced.js#L40

[4]react-use:

https://github.com/streamich/react-use/blob/master/src/useIsomorphicLayoutEffect.ts

[5]react-beautiful-dnd:

https://github.com/atlassian/react-beautiful-dnd/blob/master/src/view/use-isomorphic-layout-effect.js

[6]fix: useDocumentVisiblility support SSR:

https://github.com/alibaba/hooks/pull/935/files

[7]UmiJS 服务端渲染:

https://umijs.org/zh-CN/docs/SSR#window-is-not-defined-document-is-not-defined-navigator-is-not-defined

[8]useLayoutEffect and SSR:

https://medium.com/@alexandereardon/uselayouteffect-and-SSR-192986cdcf7a

本文转载自微信公众号「前端技术砖家」,可以通过以下二维码关注。转载本文请联系前端技术砖家公众号。

当前名称:ReactHooks在SSR模式下常见问题及解决方案
网址分享:http://www.csdahua.cn/qtweb/news46/356946.html

网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网