React 18新特性

react18 新变化

总的来说,由于新的并发特性是渐进适配并按需启用的,React 18 中的重大更改仅限于几个简单的 API 更改,以及对 React 中多个行为的稳定性和一致性的一些改进,比较重要的一点是,不再支持 IE 浏览器。包括 createRoot、hydrateRoot 等 API。它还新增了 useId、useTransition、useDeferredValue、useSyncExternalStore 和 useInsertionEffect 等 hooks,以及 Strict Mode 的更新。

1. 加载根组件的方式变化

  • 如果你继续使用 React 17 中的 ReactDOM.render() API,你将在控制台看到警告信息。

    import ReactDOM from "react-dom";
    import { BrowserRouter as RootRouter } from "react-router-dom";
    
    ReactDOM.render(
      <RootRouter>
        <App />
      </RootRouter>,
      document.getElementById("root")
    );
    // 控制台警告信息:
    Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17.
    
  • 需要替换成 React 18 的 createRoot() API。

    import ReactDOM from "react-dom/client";
    import { BrowserRouter as RootRouter } from "react-router-dom";
    const root = ReactDOM.createRoot(document.getElementById("root"));
    root.render(
      <RootRouter>
        <App />
      </RootRouter>
    );
    

2. 自动批处理

createRoot() API 新增了 this.setState 的自动批处理功能。从 React 18 开始,状态批量更新也将应用在比如在 Promise、setTimeout 回调和原生事件处理程序中。而在 React 18 之前的版本中,这些原生事件处理程序中 this.setState 都是同步更新数据,是不会自动批处理的。也就是你调用几次 setState ,组件就会渲染几次。

  • React 17 中 setState 的特点

    class App extends React.Component {
      state = {
        a: 1,
      };
      componentDidMount() {
        this.setState({
          a: 100, // 异步
        });
        setTimeout(() => {
          this.setState({ a: this.state.a + 1 }); // 同步 渲染一次
          this.setState({ a: this.state.a + 1 }); // 同步 再渲染一次
        }, 1000);
      }
      render() {
        console.log("render", this.state.a);
        return <div>test</div>;
      }
    }
    ReactDOM.render(<App />, document.getElementById("app"));
    
  • React 18 中 setState 的特点

    class App extends React.Component {
      state = {
        a: 1,
      };
      componentDidMount() {
        this.setState({
          a: 100, // 异步
        });
        setTimeout(() => {
          this.setState({ a: this.state.a + 1 }); // 异步
          this.setState({ a: this.state.a + 1 }); // 异步,合并更新
        }, 1000);
      }
      render() {
        console.log("render", this.state.a);
        return <div>test</div>;
      }
    }
    ReactDOM.render(<App />, document.getElementById("app"));
    
  • 如果需要让 this.setState 同步执行,可以通过 flushSync 函数进行强制同步执行

    import React from "react";
    import { flushSync } from "react-dom";
    
    class Home extends React.Component {
      state = {
        a: 1,
      };
      setA = () => {
        flushSync(() => {
          this.setState({ a: 100 });
        });
        flushSync(() => {
          this.setState({ a: 200 });
        });
      };
      render() {
        return (
          <div>
            <h5>Home</h5>
            <button onClick={this.setA}>setA</button>
          </div>
        );
      }
    }
    export default Home;
    

3. 并发渲染

concurrent 不算是个新鲜概念,react 很早之前就开始为其铺路,早在 v16/v17 就引入了 fiber 架构和实验性的 concurrent Mode,开启后整个应用会开启并发渲染模式,但这将带来较大的破坏性改变。因此 React 18 提出了 Concurrent Rendering 的概念,即没有并发模式,只有并发特性,也就是说并发特性只是个可选项。默认情况下整个应用仍使用同步更新(legacy 模式),在使用了并发特性后相关的更新再开启并发更新,不用的话和之前就没有任何变化。

  • 优先级分类

    • 高优先级的更新/渲染:包括鼠标点击、输入框、拖拽、移动等对实时交互性要求很高的更新场景,卡顿时会影响用户的交互行为,使用户明显感到整个页面卡顿。一般这种会使用防抖或节流来减少高频率的操作。
    • 非高优先级的更新/渲染:普通的 UI 更新,不与用户的交互相关,一些对更新实时性要求没那么高的场景。比如接口的请求。
    • React 18 为我们提供了并发渲染方式来解决这个问题:使用 starTransition 和 useTransition,只有用到这些 API 时才会开启并发更新。
  • startTransition

    用于标记非紧急的更新,用 starTransition 包裹起来就是告诉 React,这部分代码渲染的优先级不高,可以优先处理其它更重要的渲染。

  • useTransition

    除了能提供 starTransition 以外,还能提供一个变量来跟踪当前渲染的执行状态。

    import React, { useTransition, useState } from "react";
    
    function Home() {
      // 可以使用 useTransition() 钩子来创建一个 transition 过渡任务。这个钩子返回一个函数来启动一个 transition,还有一个挂起的指示器来通知你 transition 的进度。
      const [isPending, startTransition] = useTransition();
      const [value, setValue] = useState(0);
    
      function handleClick() {
        startTransition(() => {
          setValue((value) => value + 1);
        });
      }
    
      return (
        <div>
          <h5>Home</h5>
          {isPending && <div>loading...</div>}
          <p>value: {value}</p>
          <button onClick={handleClick}>handleClick</button>
        </div>
      );
    }
    export default Home;
    

4. 不常用的 hooks

以下的新 hook 主要用于解决 SSR 相关的问题或者是为第三方库的开发设计的,对于普通 React 应用开发者来说几乎用不到:

  • useId 用于解决 SSR 时客户端与服务端难以生成统一的 ID 的问题。
  • useSyncExternalStore 是一个为第三方库编写提供的新 hook,主要用于支持 React 18 在 concurrent rendering 下与第三方 store 的数据同步问题。
  • useInsertionEffect 主要用于提高第三方 CSS in JS 库渲染过程中样式注入的性能。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值