Quelles sont les différences entre le hook de réaction et la classe ?

青灯夜游
Libérer: 2022-03-22 12:12:22
original
8380 Les gens l'ont consulté

Différences : 1. Les hooks sont écrits de manière plus concise que les classes ; 2. Le code métier des hooks est plus agrégé que les classes ; 3. La réutilisation logique des composants de classe utilise généralement des accessoires de rendu et HOC, tandis que les hooks de réaction fournissent des hooks personnalisés pour réutiliser la logique. .

Quelles sont les différences entre le hook de réaction et la classe ?

L'environnement d'exploitation de ce tutoriel : système Windows 7, React version 17.0.1, ordinateur Dell G3.

Quelles sont les différences entre les hooks de réaction et les composants de classe ? Comparons les hooks de réaction et les composants de classe et parlons de leurs différences.

Problèmes résolus par les réactifs-hooks

  • Les composants fonctionnels ne peuvent pas avoir leur propre état. Avant les hooks, les composants de fonction étaient sans état et l'état du composant parent était obtenu via des accessoires, mais les hooks fournissent useState pour maintenir l'état interne du composant de fonction.

  • Le cycle de vie du composant ne peut pas être surveillé dans les composants fonctionnels. useEffect regroupe plusieurs fonctions de cycle de vie.

  • Le cycle de vie des composants de classe est plus compliqué (les changements sont gros de la version 15 à la version 16).

  • La logique des composants de classe est difficile à réutiliser (HOC, accessoires de rendu).

Avantages des hooks par rapport à la classe (comparaison)

1 La méthode d'écriture est plus concise

Nous prenons comme exemple le compteur le plus simple :

composant de classe

class ExampleOfClass extends Component {
  constructor(props) {
    super(props)
    this.state = {
      count: 1
    }
  }
  handleClick = () => {
    let { count } = this.state
    this.setState({
      count: count+1
    })
  }
  render() {
    const { count } = this.state
    return (
      <div>
        <p>you click { count }</p>
        <button onClick={this.handleClick}>点击</button>
      </div>
    )
  }
}
Copier après la connexion

hooks

function ExampleOfHooks() {
    const [count, setCount] = useState(0)
    const handleClick = () => {
        setCount(count + 1)
    }
    return (
      <div>
        <p>you click { count }</p>
        <button onClick={handleClick}>点击</button>
      </div>
    )
}
Copier après la connexion

Vous pouvez voir que le code utilisant des hooks est plus concis et clair que le code du composant de classe.

2. Le code métier est plus agrégé

Lors de l'utilisation de composants de classe, il arrive souvent qu'une fonction apparaisse dans deux fonctions de cycle de vie de cette façon, vous pouvez parfois oublier de les écrire séparément. Par exemple :

let timer = null
componentDidMount() {
    timer = setInterval(() => {
        // ...
    }, 1000)
}
// ...
componentWillUnmount() {
    if (timer) clearInterval(timer)
}
Copier après la connexion

Étant donné que l'ajout de minuteries et l'effacement des minuteries relèvent de deux fonctions de cycle de vie différentes, il peut y avoir de nombreux autres codes commerciaux entre les deux, vous risquez donc d'oublier d'effacer la minuterie si la minuterie d'effacement n'est pas ajoutée lorsque le. Le composant est désinstallé. Le fonctionnement du serveur peut provoquer des problèmes tels que des fuites de mémoire et des requêtes réseau continues.

Mais l'utilisation de hooks peut rendre le code plus centralisé, plus facile à gérer et pas facile à oublier :

useEffect(() => {
    let timer = setInterval(() => {
        // ...
    }, 1000)
    return () => {
        if (timer) clearInterval(timer)
    }
}, [//...])
Copier après la connexion

3. La réutilisation logique est pratique

La réutilisation logique des composants de classe utilise généralement des accessoires de rendu et HOC. Les hooks React fournissent des hooks personnalisés pour réutiliser la logique.

Ce qui suit est un exemple de réutilisation logique pour obtenir la position de la souris sur la page :

réutilisation des accessoires de rendu des composants de classe

import React, { Component } from &#39;react&#39;

class MousePosition extends Component {
  constructor(props) {
    super(props)
    this.state = {
      x: 0,
      y: 0
    }
  }

  handleMouseMove = (e) => {
    const { clientX, clientY } = e
    this.setState({
      x: clientX,
      y: clientY
    })
  }

  componentDidMount() {
    document.addEventListener(&#39;mousemove&#39;, this.handleMouseMove)
  }

  componentWillUnmount() {
    document.removeEventListener(&#39;mousemove&#39;, this.handleMouseMove)
  }

  render() {
    const { children } = this.props
    const { x, y } = this.state
    return(
      <div>
        {
          children({x, y})
        }
      </div>
    )
  }

}

// 使用
class Index extends Component {
  constructor(props) {
    super(props)
  }

  render() {
    return (
      <MousePosition>
        {
          ({x, y}) => {
            return (
              <div>
                <p>x:{x}, y: {y}</p>
              </div>
            )
          }
        }
      </MousePosition>
    )
  }
}

export default Index
Copier après la connexion

réutilisation des hooks personnalisés

import React, { useEffect, useState } from &#39;react&#39;

function usePosition() {
  const [x, setX] = useState(0)
  const [y, setY] = useState(0)

  const handleMouseMove = (e) => {
    const { clientX, clientY } = e
    setX(clientX)
    setY(clientY)
  } 

  useEffect(() => {
    document.addEventListener(&#39;mousemove&#39;, handleMouseMove)
    return () => {
      document.removeEventListener(&#39;mousemove&#39;, handleMouseMove)
    }
  })
  return [
    {x, y}
  ]
}

// 使用
function Index() {
  const [position] = usePosition()
  return(
    <div>
      <p>x:{position.x},y:{position.y}</p>
    </div>
  )
}

export default Index
Copier après la connexion

On voit clairement que les hooks sont utilisés Il est plus pratique de réutiliser la logique et la logique est plus claire lorsqu'elle est utilisée.

hooks Certaines utilisations courantes de l'API

1, useState

Syntaxe

const [value, setValue] = useState(0)

Cette syntaxe est la structure du tableau ES6 La première valeur du tableau est l'état déclaré et la seconde Chaque valeur. est une fonction du changement d’état.

Chaque cadre a un état indépendant

Personnellement, je comprends que l'état indépendant de chaque cadre est implémenté à l'aide de la méthode de fermeture.

function Example() {
  const [val, setVal] = useState(0)
  const timeoutFn = () => {
      setTimeout(() => {
        // 取得的值是点击按钮的状态,不是最新的状态
          console.log(val)
      }, 1000)
  }
  return (
      <>
          <p>{val}</p>
          <button onClick={()=>setVal(val+1)}>+</button>
          <button onClick={timeoutFn}>alertNumber</button>
      </>
  )
}
Copier après la connexion

Lorsque l'état ou les accessoires du composant sont mis à jour, le composant de fonction sera rappelé pour le rendu, et chaque rendu est indépendant et possède ses propres accessoires et états indépendants, ce qui n'affectera pas les autres rendus.

2. useEffect

Syntax

useEffect(() => {
    //handler function...
    
    return () => {
        // clean side effect
    }
}, [//dep...])
Copier après la connexion

useEffect reçoit une fonction de rappel et des dépendances, et la fonction de rappel à l'intérieur ne sera exécutée que lorsque les dépendances changent. useEffect est similaire aux fonctions de cycle de vie des composants de classe didMount, didUpdate et willUnmount.

Points à noter

  • useEffect est asynchrone et sera exécuté une fois le rendu du composant terminé

  • La fonction de rappel de useEffect ne peut renvoyer qu'une fonction de traitement qui efface les effets secondaires ou ne renvoie pas

  • if useEffect est transmis Si la dépendance est un tableau vide, la fonction à l'intérieur de useEffect ne sera exécutée qu'une seule fois

3 useMemo, useCallback

useMemo et useCallback sont principalement utilisés pour réduire le nombre de mises à jour des composants et optimiser les composants. performance.

  • useMemo reçoit une fonction de rappel et des dépendances, et la fonction de rappel ne sera réexécutée que lorsque les dépendances changeront.

  • useCallback reçoit une fonction de rappel et des dépendances, et renvoie la version mémorisée de la fonction de rappel. La version mémorisée ne sera remémorisée que lorsque les dépendances changeront.

Syntaxe

const memoDate = useMemo(() => data, [//dep...])
const memoCb = useCallback(() => {//...}, [//dep...])
Copier après la connexion

Lors de l'optimisation des performances des composants, nous utilisons généralement React.PureComponent pour les composants de classe. PureComponent effectuera une comparaison sur ShouldUpdate pour déterminer s'il doit être mis à jour pour les composants de fonction, nous utilisons généralement React. note. Mais lors de l'utilisation de hooks de réaction, puisque chaque mise à jour de rendu est indépendante (un nouvel état est généré), même si React.memo est utilisé, il sera toujours restitué.

比如下面这种场景,改变子组件的name值后由于父组件更新后每次都会生成新值(addAge函数会改变),所以子组件也会重新渲染。

function Parent() {
  const [name, setName] = useState(&#39;cc&#39;)
  const [age, setAge] = useState(22)

  const addAge = () => {
    setAge(age + 1)
  }

  return (
    <>
      <p>父组件</p>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <p>age: {age}</p>
      <p>-------------------------</p>
      <Child addAge={addAge} />
    </>
  )
}

const Child = memo((props) => {
  const { addAge } = props
  console.log(&#39;child component update&#39;)
  return (
    <>
      <p>子组件</p>
      <button onClick={addAge}>click</button>
    </>
  )
})
Copier après la connexion

使用useCallback优化

function Parent() {
  const [name, setName] = useState(&#39;cc&#39;)
  const [age, setAge] = useState(22)

  const addAge = useCallback(() => {
    setAge(age + 1)
  }, [age])

  return (
    <>
      <p>父组件</p>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <p>age: {age}</p>
      <p>-------------------------</p>
      <Child addAge={addAge} />
    </>
  )
}

const Child = memo((props) => {
  const { addAge } = props
  console.log(&#39;child component update&#39;)
  return (
    <>
      <p>子组件</p>
      <button onClick={addAge}>click</button>
    </>
  )
})
Copier après la connexion

只有useCallback的依赖性发生变化时,才会重新生成memorize函数。所以当改变name的状态是addAge不会变化。

4、useRef

useRef类似于react.createRef。

const node = useRef(initRef)
Copier après la connexion

useRef 返回一个可变的 ref 对象,其 current 属性被初始化为传入的参数(initRef)

作用在DOM上

const node = useRef(null)
<input ref={node} />
Copier après la connexion

这样可以通过node.current属性访问到该DOM元素。

需要注意的是useRef创建的对象在组件的整个生命周期内保持不变,也就是说每次重新渲染函数组件时,返回的ref 对象都是同一个(使用 React.createRef ,每次重新渲染组件都会重新创建 ref)。

5、useReducer

useReducer类似于redux中的reducer。

语法

const [state, dispatch] = useReducer(reducer, initstate)
Copier après la connexion

useReducer传入一个计算函数和初始化state,类似于redux。通过返回的state我们可以访问状态,通过dispatch可以对状态作修改。

const initstate = 0;
function reducer(state, action) {
  switch (action.type) {
    case &#39;increment&#39;:
      return {number: state.number + 1};
    case &#39;decrement&#39;:
      return {number: state.number - 1};
    default:
      throw new Error();
  }
}
function Counter(){
    const [state, dispatch] = useReducer(reducer, initstate);
    return (
        <>
          Count: {state.number}
          <button onClick={() => dispatch({type: &#39;increment&#39;})}>+</button>
          <button onClick={() => dispatch({type: &#39;decrement&#39;})}>-</button>
        </>
    )
}
Copier après la connexion

6、useContext

通过useContext我们可以更加方便的获取上层组件提供的context。

父组件

import React, { createContext, Children } from &#39;react&#39;
import Child from &#39;./child&#39;

export const MyContext = createContext()

export default function Parent() {

  return (
    <div>
      <p>Parent</p>
      <MyContext.Provider value={{name: &#39;cc&#39;, age: 21}}>
        <Child />
      </MyContext.Provider>
    </div>
  )
}
Copier après la connexion

子组件

import React, { useContext } from &#39;react&#39;
import { MyContext } from &#39;./parent&#39;

export default function Parent() {
  const data = useContext(MyContext) // 获取父组件提供的context
  console.log(data)
  return (
    <div>
      <p>Child</p>
    </div>
  )
}
Copier après la connexion

使用步骤

  • 父组件创建并导出context:export const MyContext = createContext()
  • 父组件使用providervalue提供值:<MyContext.provide value={{name: &#39;cc&#39;, age: 22}} />
  • 子组件导入父组件的context:import { MyContext } from &#39;./parent&#39;
  • 获取父组件提供的值:const data = useContext(MyContext)

不过在多数情况下我们都不建议使用context,因为会增加组件的耦合性。

7、useLayoutEffect

useEffect 在全部渲染完毕后才会执行;useLayoutEffect 会在 浏览器 layout之后,painting之前执行,并且会柱塞DOM;可以使用它来读取 DOM 布局并同步触发重渲染。

export default function LayoutEffect() {
  const [color, setColor] = useState(&#39;red&#39;)
  useLayoutEffect(() => {
      alert(color) // 会阻塞DOM的渲染
  });
  useEffect(() => {
      alert(color) // 不会阻塞
  })
  return (
      <>
        <div id="myDiv" style={{ background: color }}>颜色</div>
        <button onClick={() => setColor(&#39;red&#39;)}>红</button>
        <button onClick={() => setColor(&#39;yellow&#39;)}>黄</button>
      </>
  )
}
Copier après la connexion

上面的例子中useLayoutEffect会在painting之前执行,useEffect在painting之后执行。

hooks让函数组件拥有了内部状态、生命周期,使用hooks让代码更加的简介,自定义hooks方便了对逻辑的复用,并且摆脱了class组件的this问题;但是在使用hooks时会产生一些闭包问题,需要仔细使用。

【相关推荐:Redis视频教程

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal