我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

本篇文章中,苏南大叔描述另外一个非常非常非常没用非常鸡肋的react函数useInsertionEffect()。基本上没啥用,官方描述上来说,是用来挂载第三方的cssjs的,语焉不详。那么,这个超级鸡肋的react函数useInsertionEffect()是怎么使用的呢?这就是本文的主要话题。

苏南大叔:react教程,如何使用useInsertionEffect附加第三方css文件? - useInsertionEffect
react教程,如何使用useInsertionEffect附加第三方css文件?(图9-1)

苏南大叔的程序如此灵动博客,记录苏南大叔和计算机代码的故事。本文测试环境:create-react-app@5.0.1react@18.2.0react-dom@18.2.0node@16.14.2

官方描述

react官方对这个函数也不推荐使用,推荐使用useEffect或者useLayoutEffect代替。

该签名与 useEffect 相同,但它在所有 DOM 突变之前同步触发。使用它在读取 useLayoutEffect 中的布局之前将样式注入 DOM。由于这个 hook 的作用域有限,所以这个 hook 不能访问 refs,也不能安排更新。
useInsertionEffect 应仅限于 css-in-js 库作者使用。优先考虑使用 useEffect 或 useLayoutEffect 来替代。

这些文字描述比较的令人费解,暂时就这么放着吧,大家慢慢体会。先看看苏南大叔根据网上的只言片语修复的功能。本文对这个useInsertionEffect()的理解也不够深刻到位。由于这个函数的鸡肋性,就先这么看看吧。

苏南大叔:react教程,如何使用useInsertionEffect附加第三方css文件? - 官方说明
react教程,如何使用useInsertionEffect附加第三方css文件?(图9-2)

核心代码

根据目前网上的一些只言片语,苏南大叔调试了一段代码,实现了官方所描述的这个加载第三方css(js文件)的功能。

加载css文件:

let insertCSS = new Set();
function useCSS(file_name) {
  useInsertionEffect(() => {
    if (!insertCSS.has(file_name)) {
      var _css = document.createElement("link");
      _css.rel = "stylesheet";
      _css.href = file_name + ".css";
      document.head.appendChild(_css);
      insertCSS.add(file_name);
    }
  });
}

苏南大叔:react教程,如何使用useInsertionEffect附加第三方css文件? - 核心代码
react教程,如何使用useInsertionEffect附加第三方css文件?(图9-3)

加载js文件:

let insertJS = new Set();
function useJS(file_name) {
  useInsertionEffect(() => {
    if (!insertJS.has(file_name)) {
      var _js = document.createElement("script");
      _js.type = "application/x-javascript";
      _js.src = file_name + ".js";
      document.head.appendChild(_js);
      insertJS.add(file_name);
    }
  });
}

第三方文件范例

public/sunan.css:

.sunan-class {
    font-size: 22px;
    color: red;
}
.sunan-class-2 {
    font-size: 22px;
    color: blue;
}

public/sunan.js

function test(){
    alert("苏南大叔 测试!");
}

苏南大叔:react教程,如何使用useInsertionEffect附加第三方css文件? - 第三方代码
react教程,如何使用useInsertionEffect附加第三方css文件?(图9-4)

如何调用外部代码

定义了两个div,应用了第三方样式表里面的定义。然后,一个调用react自身的test(),另外一个调用第三方的test()函数。

<div className="sunan-class" onClick={() => { window.test() }}>调用传统第三方库的css</div>
<div className="sunan-class-2" onClick={test.bind()}>调用传统第三方库的css</div>

相比较传统的html写法,

  • 这里的onclick中的click首字母是大写。否则报错。
  • 调用第三方函数,不能直接写函数名,要加个window.,然后再包个匿名函数()=>{}。最后放在reactonClick={}里面,否则也各种报错函数未定义。

参考文档:
https://newsn.net/say/react-connect-html.html

苏南大叔:react教程,如何使用useInsertionEffect附加第三方css文件? - 调用外部js
react教程,如何使用useInsertionEffect附加第三方css文件?(图9-5)

完整代码

src/App.js:

import React, { useInsertionEffect } from "react";

const App = () => {
  useCSS("sunan");
  useJS("sunan");
  const test = () => {
    alert("react 测试!");
  }
  return (
    <>
      <div className="sunan-class" onClick={() => { window.test() }}>调用传统第三方库的css</div>
      <div className="sunan-class-2" onClick={test.bind()}>调用传统第三方库的css</div>
    </>
  );
}
export default App;

let insertCSS = new Set();
function useCSS(file_name) {
  useInsertionEffect(() => {
    if (!insertCSS.has(file_name)) {
      var _css = document.createElement("link");
      _css.rel = "stylesheet";
      _css.href = file_name + ".css";
      document.head.appendChild(_css);
      insertCSS.add(file_name);
    }
  });
}

let insertJS = new Set();
function useJS(file_name) {
  useInsertionEffect(() => {
    if (!insertJS.has(file_name)) {
      var _js = document.createElement("script");
      _js.type = "application/x-javascript";
      _js.src = file_name + ".js";
      document.head.appendChild(_js);
      insertJS.add(file_name);
    }
  });
}

苏南大叔:react教程,如何使用useInsertionEffect附加第三方css文件? - 运行截图
react教程,如何使用useInsertionEffect附加第三方css文件?(图9-6)

执行顺序

目前已经范例过三个Effect了,分别是:useEffect()useLayoutEffect()以及本文的useInsertionEffect()。官方其实都推荐使用useEffect()(那为啥还非要出后面这两个呢)。

useInsertionEffect的执行时机被描述为“所有 DOM 突变之前同步触发”。下面来打印一下三者的执行时间:

React.useEffect(() => {
  console.log('useEffect', performance.now().toFixed(0))
})
React.useLayoutEffect(() => {
  console.log('useLayoutEffect', performance.now().toFixed(0))
})
React.useInsertionEffect(() => {
  console.log('useInsertionEffect', performance.now().toFixed(0))
})

可见三者执行顺序是:useInsertionEffect()早于useLayoutEffect()早于useEffect()

苏南大叔:react教程,如何使用useInsertionEffect附加第三方css文件? - 执行顺序
react教程,如何使用useInsertionEffect附加第三方css文件?(图9-7)

而且,可以发现:StrictMode引发的两次渲染,也并不会触发useInsertionEffect(即使后面不添加任何,[]字样)。这个倒是个意外...

第二个例子

这里有另外一个css-in-js技术的例子,参考代码:

import React from 'react';
export const UseInsertion = () => {
  React.useInsertionEffect(() => {
    const style = document.createElement('style')
    style.innerHTML = `
      .css-in-js{
        color: blue;
        font-size: 20px;
      }
    `
    document.head.appendChild(style)
  }, [])
  return (
    <>
      <div className="css-in-js">苏南大叔</div>
    </>
  );
};

useInsertionEffect()也有第二个参数,也可以不填,或者填[]或者监控一些变量。这个很好理解,和已知的useEffect()规则一样,就仅仅是执行时机不同罢了。

苏南大叔:react教程,如何使用useInsertionEffect附加第三方css文件? - css-in-js-2
react教程,如何使用useInsertionEffect附加第三方css文件?(图9-8)

第三个例子

styled-components这个最经典的css-in-js框架,里面也使用了useInsertionEffect()。大家可以去研究一下相关代码,截图如下:

苏南大叔:react教程,如何使用useInsertionEffect附加第三方css文件? - css-in-js
react教程,如何使用useInsertionEffect附加第三方css文件?(图9-9)

参考文字:

相关链接

结束语

更多react相关经验文章,请点击:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   react