React18新特性

235 阅读2分钟

React18新特性

1.useTransition:在状态修改时不会立即更定DOM,减少视觉上的延迟,使用体验更加丝滑,性能方面也会更好。例如对于输入框,如果将其写为可控组件,那么在输入值过程中,输入框这个DOM也在同步更新,而使用useTransition之后,可以将其改为无需完全同步,使得输入起来更加的平滑。将修改状态的代入写入startTransition的回调函数内即可。

import React, { useState, useTransition } from "react";

export default function SearchCities() {
  const [text, setText] = useState("Am");
  const [searchQuery, setSearchQuery] = useState(text);
  const [isPending, startTransition] = useTransition();

  return (    
    <main>          
      <input  
        type="text" 
        value={text}
        onChange={(e) => {
          setText(e.target.value)
          startTransition(() => {
            setSearchQuery(e.target.value)
          })
        }}  
      />      
      <CityList searchQuery={searchQuery} />    
    </main>  
  );
};

2.新增client和server:前者是客户端渲染,后者是服务端渲染

import React from 'react';
import ReactDOM from 'react-dom/client';
import ReactDOM from 'react-dom/server';
import App from './App';

const root = document.getElementById('root');
ReactDOM.createRoot(root).render(<App />);

3.对于ts提示,所有组件需要手动写Children的类型,系统将不再自带

interface MyButtonProps {
  color: string;
  children?: React.ReactNode;
}

const MyButton: React.FC<MyButtonProps> = ({ color, children }) => {
  return <div>{children}</div>;
};

export default MyButton;

4.flushSync:清除批量更新。React特性在同步代码中,所有的状态改变都是一次性批量处理的,这样DOM只用更新一遍。但对于特殊的情况是需要退出批量更新的,这时候可以把状态变化相关的代码放到flushSync的回调函数中。回调函数中为批量更新,函数之外就不是了。

function handleClick() {
  flushSync(() => {
    // 批量更新
    setCount(3);
    setFlag(true);
  });
  以上批量更新完成之后,再进行以下状态的更新
  setLoading(false);
}

5.useDeferredValue:用于延迟更新组件状态,可以自定义配置延迟时间,以降低这部分状态带来的页面重新渲染的优先级。所以当遇到部分渲染优先级处于最低的状态,使用useDeferredValue即可。

useDeferredValue 与 useTransition的异同:

  • 同:useDeferredValue 本质上和内部实现与 useTransition 一样都是标记成了非紧急更新任务。
  • 异:useTransition 是把更新任务变成了延迟更新任务,而 useDeferredValue 是产生一个新的值,这个值作为延时状态.

useDeferredValue 与 debounce的区别:debounce 即 setTimeout 总是会有一个固定的延迟,而 useDeferredValue 的值只会在渲染耗费的时间下滞后,在性能好的机器上,延迟会变少,反之则变长。

import React, { useState, useDeferredValue } from 'react';
const App = () => {
  const [count, setCount] = useState(0);
  const deferredCount = useDeferredValue(count, { timeoutMs: 500 });
  function handleClick() {
    setCount(count + 1);
  }
  return (
    <>
      <div>{deferredCount}</div>
      <button onClick={handleClick}>+1</button>
    </>
  );
}
export default App;

6.useId:用于解决 SSR 时客户端与服务端难以生成统一的 ID 的问题。因为服务器渲染时提供的html是无序的,useId 的原理就是每个id代表该组件在组件树中的层级结构。

import React, { useId } from 'react';
const App = () => {
  const id = useId();
  return (
    <div>useId</div>
  );
}
export default App;

7.useInsertionEffect:一般只用于css-in-js库相关。这个hooks是在dom生成并完全挂载之前执行,一般运用在提前挂载style脚本。

const useCSS = rule => {
  useInsertionEffect(() => {
    if (!isInserted.has(rule)) {
      isInserted.add(rule);
      document.head.appendChild(getStyleForRule(rule));
    }
  });
  return rule;
};

const App: React.FC = () => {
  const className = useCSS(rule);
  return <div className={className} />;
};

export default App;