Skip to content

react

react,Api分为 组件类 工具类 hooks react-dom 一共四个方向,加以讨论:

组件类

组件类分为三种类型:

  1. 继承基类的组件:Component PureComponent
  2. 高阶组件:memo forwardRef
  3. 内置的组件:Fragment StrictMode Suspense Profiler(这个是React Developer Tools内置组件)

Component

Componentclass组件的根基.类组件的一切始于Component

ts
class Index extends React.Component{
    constructor(props){
        super(props)
        this.state={
           data:{
              name:'alien',
              age:28
           }
        }
    }
    handerClick= () =>{
        const { data } = this.state
        data.age++
        this.setState({ data })
    }
    render(){
        const { data } = this.state
        return <div className="box">
        <div className="show" >
            <div> 你的姓名是: { data.name } </div>
            <div> 年龄: { data.age  }</div>
            <button onClick={ this.handerClick } >age++</button>
        </div>
    </div>
    }
}

PureComponet

PureComponet被称为纯组件,使用方法跟Component一样,作用是避免不必要的render,提高性能;

memo

memoPureComponet类似;作用是用于函数式组件;也是避免不必要的render,对于props进行浅比较也就是使用Object.is比较;

未使用memo的版本:

react更新组件的机制导致react内部无法知道那个组件跟新,所以会出现组件props未变化,但是组件进行重新render的情况:

tsx
import { FC, useState } from "react"

function App() {
  const [str, setStr] = useState('')

  return <>
    {/* 输入导致跟新 */}
    <input value={str} onChange={(e) => setStr(e.target.value)} />
    <div>{str}</div>
    <Counter count={0} />
  </>
}

const Counter: FC<{ count: number }> = (props) => {
  console.log('渲染counter');
  const { count } = props
  return <>
    {count}
  </>
}

export default App

使用memo的版本:

WARNING

  1. Object.is({},{})返回false
  2. Object.is([],[])返回false
tsx
import { FC, memo, useState } from "react"

function App() {
  const [str, setStr] = useState('')

  return <>
    {/* 输入导致跟新 */}
    <input value={str} onChange={(e) => setStr(e.target.value)} />
    <div>{str}</div>
    <Counter count={0} />
  </>
}
/* memo进行缓存 */
const Counter: FC<{ count: number }> = memo((props) => {
  console.log('渲染counter');
  const { count } = props
  return <>
    {count}
  </>
})

export default App
思考:如果传入的是一个对象或者是一个array的时候该怎么办呢?

为了最大化使用 memo 的效果,应该尽量减少 props 的变化次数。例如,如果 props 是一个对象,可以使用 useMemo 避免父组件每次都重新创建该对象:

tsx
import { memo, useMemo, useState } from "react"

function App() {
  const [str, setStr] = useState('')
  /* 这里使用useMemo缓存array */
  const avatars = useMemo(() => {
    return Array.from({ length: 4 }, (_, index) => {
      return `https://picsum.photos/50/50?random=${index}`
    })
  }, [])

  return <>
    {/* 输入导致跟新 */}
    <input value={str} onChange={(e) => setStr(e.target.value)} />
    <div>{str}</div>
    <AvatarList avatars={avatars} />
  </>
}


const AvatarList = memo((props: { avatars: Array<string> }) => {
  const { avatars } = props
  console.log('渲染list') /* 只有初次渲染会触发 */
  return <>
    {avatars.map((avatar, i) => <img src={avatar} key={i} className="w-100px h-100px  rounded-full m-2" />)}
  </>
})

export default App

forwardRef

forwardRef 允许组件使用 refDOM 节点暴露给父组件

tsx
import { forwardRef, useRef } from "react"

function App() {
  const videoRef = useRef<HTMLVideoElement | null>(null)
  const videoProps = {
    src: 'https://www.w3schools.com/html/mov_bbb.mp4',
    type: 'video/mp4',
    width: 500
  }

  function handlePlay() {
    videoRef.current?.play()
  }

  function handlePause() {
    videoRef.current?.pause()
  }
  return <>
    <div>
      <button onClick={handlePlay}>play</button>
      <button onClick={handlePause}>pause</button>
    </div>
    <MyVideoPlayer ref={videoRef} {...videoProps} />
  </>
}
type IProps = {
  src: string,
  type: string,
  width: number
}

const MyVideoPlayer = forwardRef<HTMLVideoElement, IProps>((props: IProps, ref) => {
  const { src, type, width } = props
  /* 向外面暴露属性 
  useImperativeHandle(ref, {
    
  }, [])
  */
  return <video ref={ref} width={width} controls={true}>
    <source
      src={src}
      type={type}
    />
  </video>

})

Fragment (<>...</>)

<Fragment> 通常使用 <>...</> 代替,它们都允许你在不添加额外节点的情况下将子元素组合。

tsx
<>
  <OneChild />
  <AnotherChild />
</>

WARNING

只有需要key的时候Fragment才需要完整写不然就是<>...</>代替

例如:

tsx
function DateRangePicker({list}){
  return (list.map(({start,end},index)=>{
    return <Fragment key={index}>
       From
      <DatePicker date={start} />
      to
      <DatePicker date={end} />
    </Fragment>
  }))
}

StrictMode

StrictMode 帮助你在开发过程中尽早地发现组件中的常见错误。

tsx
<StrictMode>
  <App />
</StrictMode>

StrictMode严格模式,在开发环境中会调用一些函数两次(仅限应为纯函数的函数)。这些函数包括:

  1. 组件函数体(仅限顶层逻辑,不包括事件处理程序内的代码)
  2. 传递给 useState set 函数 函数、useMemo useReducer 的函数
  3. 部分类组件的方法

Suspense

Suspense允许在子组件完成加载前展示后备方案。

WARNING

实验组件,后续会出use来包裹进行更好的使用

tsx
<Suspense fallback={<Loading />}>
  <SomeComponent />
</Suspense>

//todo

参考链接

react官方文档