目录

  • 升级18
  • Automatic Batching⾃动批量更新 state,减少渲染次数(系统优化)
  • Concurrent Mode(系统优化)
  • Transition (新api)
  • Suspense (新api)

升级18

只需要调整根节点的挂载,别的代码无不兼容调整。

  1. // ==> 18之前
  2. import { render } from "react-dom";
  3. const container = document.getElementById('app');
  4. render(<App tab="home" >, container);
  5. // ==> 18之后
  6. import { createRoot } from "react-dom/client";
  7. const container = document.getElementById('app');
  8. const root = createRoot(container);
  9. root.render(<App tab="home" >);

在18中使用旧版也可以兼容,不过会有warning提示
image.png

Automatic Batching

⾃动批量更新 state,减少渲染次数;
系统框架优化,使用者无感;

// Before
setTimeout(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // React will render twice, once for each state update (no batching)
}, 1000);
// After
setTimeout(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // React will only re-render once at the end (that's batching!)
}, 1000);

如果想要禁用这个优化可以使用flushSync,这样就和18之前一样,每次状态变更都会触发render

import { flushSync } from 'react-dom';
function handleClick() {
  flushSync(() => {
    setCounter(c => c + 1);
  });
  // React has updated the DOM by now
  flushSync(() => {
    setFlag(f => !f);
  });
  // React has updated the DOM by now
}

Concurrent Mode

Concurrent —— 并发渲染

  • 渲染可以被中断,继续,终⽌的
  • 渲染可以在后台进⾏
  • 渲染可以有优先级
  • 不是新功能,⽽是⼀种新的底层机制

image.png

Transition (新api)

const [isPending, startTransition] = useTransition();
startTransition包裹的将会是底优先级的渲染,isPending标识在渲染过程中
https://codesandbox.io/s/search-pokemons-optimized-tcrtt?file=/src/searchPokemons/SearchPokemonsOptimized.js:0-1037

import { Input } from "@material-ui/core";
import React, { useState, useTransition } from "react";
import { makeStyles } from "@material-ui/styles";
import CircularProgress from "@material-ui/core/CircularProgress";

import PokemonsCard from "../common/PokemonsCard";

const useStyles = makeStyles({
  spinner: {
    height: "15px !important",
    width: "15px !important",
    position: "relative",
    top: 10,
    left: 10
  }
});

const SearchPokemonsOptimized = () => {
  const [text, setText] = useState("");
  const [searchQuery, setSearchQuery] = useState("");
  const [isPending, startTransition] = useTransition();
  const classes = useStyles();

  const onChange = (e) => {
    setText(e.target.value);
    startTransition(() => {
      setSearchQuery(e.target.value);
    });
  };

  return (
    <>
      <Input onChange={onChange} value={text} />
      {isPending && <CircularProgress className={classes.spinner} />}
      <PokemonsCard searchQuery={searchQuery} />
    </>
  );
};

export default SearchPokemonsOptimized;

Transitions——总结

  • 区别渲染优先级
  • 应对同时有⼤量渲染的情况

这里可以减少上边输入框每次输入文字都触发搜索触发渲染的性能损耗;

Suspense (新api)

边渲染边获取数据

const resource = fetchProfileData();


function ProfileDetails() {
    const user = resource.user.read();
    return <h1>{user.name} /h1>;
}

function ProfilePage() {
    return (
        <Suspense fallback={<h1>Loading profile . /h1>}>
            <ProfileDetails >
            <Suspense fallback={<h1>Loading posts . /h1>}>
                <ProfileTimeline >
            </Suspense>
        </Suspense>
    );
}

// 想要改变渲染方式是,只需要调整Suspense的嵌套关系,↓调整为同步渲染

function ProfilePage() {
    return (
        <div>
            <Suspense fallback={<h1>Loading profile . /h1>}>
                <ProfileDetails >
            </Suspense>
            <Suspense fallback={<h1>Loading posts . /h1>}>
                <ProfileTimeline >
            </Suspense>
        </div>
    );
}

原文

https://x140yu.notion.site/x140yu/8e8c6a9973a04a9cbb2974422a738a84?p=d81812e704364ed0a25694800d6eb8ca

03 - React 18.pdf