第六十四周总结——React18新特性的hook

React18新特性的hook

useId

    useId解决了客户端和服务端id不相同的问题。

    我们看下面这段代码

function App() {
  return (
    <>
      <Checkbox />
      <Checkbox />
    </>
  );
}

function Checkbox() {
  return (
    <>
      <label htmlFor="1">Do you like React?</label>
      <input type="checkbox" name="react" id="1" />
    </>
  );
}

export default App;

    上面代码我们会发现Checkbox组件复用,会导致出现两个相同的id。会报一个错误IDs used in ARIA and labels must be unique: Document has multiple elements referenced with ARIA with the same id attribute: 1。那我们怎么解决这个问题呢?来看下面这段代码。

function App() {
  return (
    <>
      <Checkbox />
      <Checkbox />
    </>
  );
}

function Checkbox() {

  const id = Math.random() + "";

  return (
    <>
      <label htmlFor={id}>Do you like React?</label>
      <input type="checkbox" name="react" id={id} />
    </>
  );
}

export default App;

    使用随机数来代替固定的id使得没有报错,但是这仍然有问题,如果恰好两次随机到了一个数,或者当使用服务端渲染的时候,客户端和服务端的id就不相同了。于是在React18版本就退出了useId这个hook。

import { useId } from 'react';
function App() {
  return (
    <>
      <Checkbox />
      <Checkbox />
    </>
  );
}

function Checkbox() {

  const id = useId();

  return (
    <>
      <label htmlFor={id}>Do you like React?</label>
      <input type="checkbox" name="react" id={id} />
    </>
  );
}

export default App;

    上面React渲染成真实DOM后就成了下面的代码。

<div id="root">
    <label for=":r1:">Do you like React?</label><input type="checkbox" name="react" id=":r1:">
    <label for=":r3:">Do you like React?</label><input type="checkbox" name="react" id=":r3:">
</div>

    useId的原理就是每个id代表组件在组件树种的层级结构。

useTransition

    在React的状态更新中分为紧急更新和过渡更新。

  • 紧急更新,输出、点击、拖拽等事件需要立即响应,不然就会有种很卡的感觉。
  • 过渡更新,将UI从一个视图过渡到另一个视图,可以有些延迟。

    并发模式只是提供了可中断的能力,默认情况下,所有的更新都是紧急更新,也就是更新的优先级相同。那么快速更新还是会被其他大量更新拖慢速度。我们看下面代码的示例。

import { useEffect, useState } from "react";

function App() {

  const [value, setValue] = useState('');

  return (
    <>
      <input type="text" value={value} onChange={(e)=>{
        setValue(e.target.value)
      }} />
      <List search={value} />
    </>
  );
}

function List({search}:{search: string}){

  const [list, setList] = useState<string[]>([]);

  useEffect(()=>{
    setTimeout(()=>{
      setList(new Array(5000).fill(""))
    },100)
  },[search])

  return <ul>
    {
      list.map((_,index) => {
        return <Item key={index} value={index+"_"+search} />
      })
    }
  </ul>
}

function Item({value}:{value: string}){
  return (
    <li>{value}</li>
  )
}

export default App;

    因为上面有5000条数据,每次都search改变100毫秒后都会重新渲染。当输入的速度很快的时候就会导致输入框特别的卡。这是因为输入框的更新优先级和列表的更新优先级是一样的,那有没有一种可能,我们将输入框的优先级提高,这样列表就不会立刻渲染,只有当输入框输入事件不再触发的时候才会渲染呢。

import { useEffect, useState, startTransition } from "react";

function App() {

  const [value, setValue] = useState('');
  const [search, setSearch] = useState('');

  return (
    <>
      <input type="text" value={value} onChange={(e)=>{
        setValue(e.target.value)// 紧急任务
        startTransition(()=>{
          setSearch(e.target.value)// 非紧急任务
        })
      }} />
      <List search={search} />
    </>
  );
}

function List({search}:{search: string}){

  const [list, setList] = useState<string[]>([]);

  useEffect(()=>{
    setTimeout(()=>{
      setList(new Array(5000).fill(""))
    },100)
  },[search])

  return <ul>
    {
      list.map((_,index) => {
        return <Item key={index} value={index+"_"+search} />
      })
    }
  </ul>
}

function Item({value}:{value: string}){
  return (
    <li>{value}</li>
  )
}

export default App;

    使用startTransition将search状态更新变成非优先级任务,还会出现节流的效果。我们使用useTransition来替代startTransition试一试。

import { useEffect, useState, useTransition } from 'react';

function App() {

  const [value, setValue] = useState('');
  const [search, setSearch] = useState('');
  const [isPending, startTransition] = useTransition();

  return (
    <>
      <input type="text" value={value} onChange={(e)=>{
        setValue(e.target.value)// 紧急任务
        startTransition(()=>{
          setSearch(e.target.value)// 非紧急任务
        })
      }} />
      {isPending && 'loading……'}{/* 非紧急任务的状态 */}
      <List search={search} />
    </>
  );
}

function List({search}:{search: string}){

  const [list, setList] = useState<string[]>([]);

  useEffect(()=>{
    setTimeout(()=>{
      setList(new Array(5000).fill(""))
    },100)
  },[search])

  return <ul>
    {
      list.map((_,index) => {
        return <Item key={index} value={index+"_"+search} />
      })
    }
  </ul>
}

function Item({value}:{value: string}){
  return (
    <li>{value}</li>
  )
}

export default App;

useDeferredValue

    除了useTransition我们还可以使用useDeferredValue将任务变成非紧急状态

import { useEffect, useState, useDeferredValue } from 'react';

function App() {

  const [value, setValue] = useState('');
  const [search, setSearch] = useState('');

  return (
    <>
      <input type="text" value={value} onChange={(e)=>{
        setValue(e.target.value)// 紧急任务
        setSearch(e.target.value)
      }} />
      <List search={useDeferredValue(search)} />{/* 标记非紧急状态 */}
    </>
  );
}

function List({search}:{search: string}){

  const [list, setList] = useState<string[]>([]);

  useEffect(()=>{
    setTimeout(()=>{
      setList(new Array(5000).fill(""))
    },100)
  },[search])

  return <ul>
    {
      list.map((_,index) => {
        return <Item key={index} value={index+"_"+search} />
      })
    }
  </ul>
}

function Item({value}:{value: string}){
  return (
    <li>{value}</li>
  )
}

export default App;

useDeferredValue与useTransition的区别

  • 不同点:useDeferredValue是把更新任务变成了延迟更新任务,而useTransition是把一个状态变成了延迟状态
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值