[React Hooks] Освойте и сравните 8 часто используемых хуков (оптимизация и сценарии использования)

React.js
[React Hooks] Освойте и сравните 8 часто используемых хуков (оптимизация и сценарии использования)

предисловие

Я давно не писал статьи, подытожу и запишу восемь вещей, которые я обычно использую или которые, как мне кажется, мне следует освоить.React Hooks.如果算上自定义Hooks, должно быть девять, но эта статья не будет расширяться. Я только что узнал, прежде чем пришел в NetEaseReactFramework, я просмотрел проект компании в течение дня, а затем обнаружил, что мне нужно взглянутьReact Hooks, Я посмотрел его на выходных, сделал резюме и поделился им здесь. Эта статья для каждогоHooksОни объединены с примерами и сценариями использования, чтобы объяснить, немного долго, вы можете сосредоточиться на том, что хотите узнать.HooksЕсть цель увидеть.

React Hooks

1 useState

1.1 Компоненты класса

В компоненте класса вы можете использоватьthis.stateЧтобы определить состояние компонента класса, вы можете увидеть следующую реализацию кода

import React from 'react'

class StateClass extends React.Component{
    constructor(){
        super()
        this.state = {
            name: '类'
        }
    }

    render() {
        return (
            <div onClick={ this.setName }>
                这是一个类组件————{ this.state.name }
            </div>
        )
    }

    setName = () => {
        this.setState({
            name: '我通过类组件方法变成这样了'
        })
    }
}

export default StateClass

1.2 Функциональные компоненты

В функциональном компоненте вы можете использоватьuseStateдля определения состояния функционального компонента. использоватьuseStateсоздать государство

  • 1. Представьте
  • 2. Получить параметр как начальное значение
  • 3. Вернуть массив, первое значение — состояние, а второе значение — функция, меняющая состояние

Взгляните на ту же реализацию функции, функциональный компонентuseStateРеализация кода следующая. Та же функциональность, используя функциональные компонентыuseStateУдобнее писать? Далее продолжаем изучать другиеhooks

import React,{ useState } from 'react'

function StateFunction () {
    const [name, setName] = useState('函数')
    //     类名,修改函数名            初始值

    return (
        <div onClick={ () => setName('我使用hooks变成这样了') }>
        //	setName也可以写入方法,如setName( val => val+'xxxx' )
            这是一个函数式组件————{name}
        </div>
    )
}

export default StateFunction

2 useEffect

2.1 Краткое введение

useEffectон же побочный эффектhooks.作用:给没有生命周期的组件,添加结束渲染的信号。执行时机:在渲染结束之后执行

  • Что такое побочные эффекты?

    • Побочные эффекты: выборка данных, подписка на данные и ручное изменение DOM в компонентах React — все это побочные эффекты.
    • Поскольку страницы, которые мы отображаем, являются статическими, любые последующие операции будут влиять на них, поэтому они называются побочными эффектами.
  • использовать:

    • 1. Первый параметр, получение функции в качестве параметра
    • 2. Второй параметр, получая [список зависимостей], функция будет выполняться только при обновлении зависимости
    • 3. Возврат функции, выполнить функцию возврата, затем параметр выполнения функций

2.2 Не принимайте второй параметры

Если второй параметр не принят, он будет вызываться после первого рендеринга и при каждом обновлении отображаемой страницы.useEffectФункция обратного вызова, поэтому нужно учитывать сценарий использования.

import React,{ useEffect, useState } from 'react'

function StateFunction () {
    const [num, setNum] = useState(0)
    
    useEffect( () => {
        console.log('2222函数式组件结束渲染')
    })
    
    return (
        <div onClick={ () => setNum( num => num+1 ) }>
            这是一个函数式组件————{num}
        </div>
    )
}

2.3 В случае принятия второго параметра

useEffect( () => {
    console.log('2222函数式组件结束渲染')
},[])
//	改变useEffect第二个参数,其余代码同上

Здесь мы можем передать массив второму параметру, который представляет собой список зависимостей для выполнения обновления, только при изменении списка зависимостей (при изменении любого элемента в массиве будет повторно выполнен useEffect), вызовет обратный вызов функция

  • Входящий массив пуст[], тогда расскажиuseEffectЭто не зависит отstate,propsлюбое значение в ,useEffectОн запустится только один раз, здесь можно написать метод получения данных для страницы в общих сценариях и вызвать его для получения исходных данных страницы.
  • Передайте массив значений или массив из нескольких значений, например[num],[num,val], приведенный выше код заменяется следующим. Затем, только когда значение в массиве (любой элемент) изменится, функция обратного вызова будет повторно запущена.
    useEffect( () => {
        console.log('2222函数式组件结束渲染')
    },[num])
    
    useEffect( () => {
        console.log('2222函数式组件结束渲染')
    },[num,val])
    //	改变useEffect第二个参数,其余代码同上
    

2.4 Четкие побочные эффекты

Выше приведены некоторые побочные эффекты, которые не нужно сбрасывать, но обратный вызов запускает некоторые простые методы, но есть некоторые побочные эффекты, которые необходимо сбрасывать. Например, чтобы связать некоторыеDOMСобытия, в данном случае работа по очистке очень важна для предотвращения утечек памяти, например, сравнение кода, приведенное ниже.

  • Без очистки побочных эффектов. В это время щелкните обычный вывод один раз в первый раз.打印当前位置, а потом каждый разuseEffectЗвонки привяжут новыйupdateMouseметод, то есть все больше и больше методов привязки, запускаемых одним щелчком мыши, и тогда он будет печатать как сумасшедший после одного щелчка打印当前位置, что также вызывает такие проблемы, как производительность страницы и утечки памяти.
    const [positions,setPositions] = useState({ x:0,y:0 })
    
    useEffect( () => {
        console.log('2222函数式组件结束渲染')
    
        const updateMouse = (e) => {
            console.log('打印当前位置')
            setPositions({ x:e.clientX, y:e.clientY })
        }
        document.addEventListener('click',updateMouse)
    })
    
    return (
        <div>
            <p>x:{ positions.x }</p>
            <p>y:{ positions.y }</p>
        </div>
    )
    
  • С явными побочными эффектами(Измените только часть кода, остальные коды такие же, как указано выше). пример кода
    • В первый раз или обновить страницу для входа будет сначала выполняться в дополнение кreturnкроме содержимого, то есть будет выполнен связанный метод, а затемupdateMouseметод привязан кclickмероприятие

    • и воляизменить порядокuseEffectСобытие в событии очищается и возвращается, но в это время не выполняетсяreturnСодержание контента (фокус на)

    • Затем, когда вы щелкнете в первый раз, он распечатает и установит текущие координаты страницы мыши, а затем выполнит последний разreturnСодержимое возвращено, обратите внимание, что это последнее выполнениеreturnМетод привязки четких событий, а затем выполните метод привязки четких событий, конечно, четкий также является предыдущим.useEffectобязательные события в

    • Затем начните выполнять новыйuseEffectв методе события привязки и сноваuseEffectМетоды очистки привязок событийreturnВернитесь назад, образуя цепной процесс

    • Когда страница выгружается, она будет выполняться в последний разreturnВозвращаемый метод очистки привязок событий, который гарантирует, что при выгрузке страницы добавленные привязки будут удалены.DOMметод события

    • (Процесс выполнения, написанный выше, не анализируется из принципа, а представляет собой простое описание. Оно может быть немного запутанным. Если вы не можете его понять, вы можете прочитать его несколько раз и выполнить пример кода, чтобы понять его.)

    useEffect( () => {
        console.log('2222函数式组件结束渲染')
        const updateMouse = (e) => {
            console.log('打印当前位置')
            setPositions({ x:e.clientX, y:e.clientY })
        }
        document.addEventListener('click',updateMouse) //  添加绑定方法事件(要修改依赖,绑定到依赖上)
    
        return () => {
            //  在每次执行useEffect之前都会执行上一次return中内容
            document.removeEventListener('click',updateMouse)
            //  移除绑定方法事件(要修改依赖,绑定到依赖上)
            console.log('1111销毁')
        }
    })
    

2.5 Асинхронность в использовании Эффект

Каждая функция Эффекта относится к определенному рендерингу:

  • ① Планирование useEffect не будет блокировать браузер для обновления экрана
  • ② Каждый раз при повторном рендеринге будет создаваться новый эффект, а предыдущий будет заменяться, чтобы гарантировать, что значение, полученное в эффекте, является последним, и вам не нужно беспокоиться об истечении срока действия. следующим образом, установите3000Нажмите три раза подряд в течение миллисекунд, затем будет напечатано всего 4 раза, которые0、1、2、3,0Он автоматически срабатывает после первого рендеринга, а остальные1、2、3щелкает три раза каждый раз, когда триггерcountстоимость
    function Counter() {
      const [count, setCount] = useState(0);
    
      useEffect(() => {
        setTimeout(() => {
          console.log(`${count}`);
        }, 3000);
      });
    
      return (
        <div>
          <p>你点击了{count}次</p>
          <button onClick={() => setCount(count + 1)}>
            点击我
          </button>
        </div>
      );
    }
    
    • Контраст с компонентами класса: Если он размещен в компоненте класса, это окончательное значение, измененное во время печати настройки.Эквивалентный код в компоненте класса выглядит следующим образом (дан только код ключа). Что значит напечатать окончательное значение, измененное за установленное время? Если вы установите 3000 миллисекунд, отсчет времени начнется в момент окончания рендеринга, а если вы нажмете три раза подряд в течение 3000 миллисекунд, вы в итоге напечатаете 4 раза.3, если ждать в первый разcomponentDidMountПосле того, как таймер установлен в , а затем внезапно нажмите три раза подряд в течение 3000 миллисекунд, первый раз будет напечатан первым.0, напечатайте еще три раза3,Потому что класс написан в одном и том жеnumзначение состояния. (если вы установите время на0миллисекунд, то на самом деле, если нажать три раза подряд, последуетuseEffectТо же самое, также напечатать один раз0, а затем распечатать1、2、3, так как это изменение очень быстро реагирует, разницы не почувствуешь, можешь попробовать сам. )
      this.state = {
        	num:0
      }
      
      componentDidMount(){
          setTimeout(() => {
              console.log(this.state.num)
          },3000)
      }
      
      componentDidUpdate(){
          setTimeout(() => {
              console.log(this.state.num)
          },3000)
      }
      
      render() {
          return (
              <div onClick={ this.setNum }>
                  这是一个类组件————{ this.state.num }
              </div>
          )
      }
      
      setNum = () => {
          this.setState({
              num: this.state.num+1
          })
      }
      

3 useLayoutEffect

обычноuseLayoutEffectназывается естьDOMпобочные эффекты операцийhooks. роль вDOMВыполните действие после завершения обновления. Время выполнения: вDOMВыполнить после обновления

а такжеuseEffectВ сравнении

  • Та же точка
    • 1. Первый параметр, получение функции в качестве параметра
    • 2. Второй параметр, получая [список зависимостей], функция будет выполняться только при обновлении зависимости
    • 3. Вернуть функцию, сначала выполнить функцию возврата, а затем выполнить функцию параметра.
    • (Так что процесс выполнения тот же)
  • разница
    • Сроки исполнения разные.useLayoutEffectсуществуетDOMВыполнить после обновления;useEffectсуществуетrenderВыполняется после завершения рендеринга. Выполните пример кода, и вы найдетеuseLayoutEffectвсегда лучше, чемuseEffectвыполнить сначала, потому чтоDOMПосле обновления рендеринг заканчивается или рендеринг завершится
const [num, setNum] = useState(0)
//在类组件中用componentWillMount生命周期来实现
useLayoutEffect( () => {
    console.log('useLayoutEfffect')
	//	也可以在此进行事件绑定
    return () => {
    	//	也可以在此进行事件绑定移除
        console.log(1)
    }
},[num])

useEffect( () => {
    console.log('useEffect')
},[num])

return (
    <div onClick={ () => setNum( num => num+1 ) }>
        这是一个函数式组件————{num}
    </div>
)

4 useMemo

использоватьuseMemoВы можете передать функцию создания и зависимости. Функция создания должна будет вернуть значение. Только когда зависимости изменятся, эта функция будет вызываться снова и возвращать новое значение. Проще говоря, роль состоит в том, чтобы позволить функциям в компоненте следовать за обновлением состояния (то есть оптимизировать функции функций в функциональном компоненте).

  • использовать:
    • 1. Получить функцию в качестве параметра
    • 2. Также получите второй параметр в виде списка зависимостей (можно сравнить и изучить с помощью useEffect и useLayoutEffect)
    • 3. Возврат — это ценность. Возвращаемое значение может быть чем угодно, функциями, объектами и т.д.

4.1 Сценарии использования оптимизации сложной вычислительной логики

  • Код до оптимизации выглядит следующим образом. когда мы нажимаемdivобласти, когда триггерsetAge, изменениеage,а такжеgetDoubleNumСпособ на самом деле неактуален, но если вы посмотрите на консоль, то увидите, что он печатается несколько раз获取双倍Num, что говорит о том, что метод срабатывает постоянно, на самом деле срабатывать не нужно. Если объем вычислений в методе велик, это окажет определенное влияние на производительность, поэтому его необходимо оптимизировать.
    const [num, setNum] = useState(1)
    const [age, setAge] = useState(18)
    
    function getDoubleNum () {
        console.log(`获取双倍Num${num}`)
        return 2 * num  //	假设为复杂计算逻辑
    }
    
    return (
      <div onClick={ () => { setAge( age => age+1 )} }>
          <br></br>
          这是一个函数式组件————{  getDoubleNum() }
          <br></br>
          age的值为————{ age }
          <br></br>
      </div>
    )
    
  • использоватьuseMemoОптимизированный код выглядит следующим образом. В настоящее времяgetDoubleNumМетод заключается в получении возвращаемого значения, поэтому обратите внимание на то, что написано в комментариях, скобки убраны. использоватьuseMemo, затем нажмитеdivизменение площадиageЗначение , в это время выполнение возвращаетreturn 2*numа также печать только в том случае, еслиnumОн будет выполняться при обновлении, а затем возвращаемое значение будет передано вgetDoubleNumЗатем визуализируйте его в представлении, что сокращает ненужные вычисления для достижения оптимизации.
    const [num, setNum] = useState(1)
    const [age, setAge] = useState(18)
    
    const getDoubleNum = useMemo( () => {
        console.log(`获取双倍Num${num}`)
        return 2 * num  //	假设为复杂计算逻辑
    },[num] )
    
    return (
        <div onClick={ () => { setAge( age => age+1 ) }  }>
            <br></br>
            这是一个函数式组件————num:{  getDoubleNum }  //  注意这里没括号,因为是返回值
            <br></br>
            age的值为————{ age }
            <br></br>
        </div>
    )
    

4.2 Оптимизированные сценарии использования для повторного рендеринга родительских и дочерних компонентов

  • Код до оптимизации выглядит следующим образом. дочерний компонент оборачиваетmemo, но пакет все равно перерендерится, почему? потому что мы определяемinfoдаconstОпределена локальная переменная, каждый повторный рендеринг переопределяет новуюinfo, а затем, когда подкомпонент выполняет поверхностное сравнение,infoЭто никогда не будет прежним, поэтому он будет переназначен (вы можете нажать кнопку в соответствии с примером, и вы обнаружите, что дочерний компонент продолжает печать我是子组件). Если подкомпоненты более сложные, это повлияет на производительность страницы.
    const Child = memo( () => {
        console.log('我是子组件')
        return <p>我是子组件</p>
    })
    
    function Parent() {
        const [show,setShow] = useState(true)
    
        const info = {
            name: 'Even',
            age: 22
        }
    
        return(
            <div>
                <Child info={ info } />
                <button onClick={ () => setShow(!show) }>点击更新状态</button>
            </div>
        )
    }
    
  • использоватьuseMemoПочтовый индекс выглядит следующим образом (дан только измененный код, остальные коды такие же, как в приведенных выше примерах). После этой оптимизации дочерний компонент будет отображаться только один раз в состоянии инициализации, когда мы нажимаем кнопку, потому чтоinfoего завернутыйuseMemoЗависимость не изменилась, возвращаемое значение такое же, поэтому дочерний компонент не будет перерисовываться.
    const info = useMemo( () => {
        return {
            name: 'Even',
            age: 22
        }
    },[])
    

5 useCallback

useMemoПосле того, как мы закончим разговор, давайте поговорим об очень похожем имени.useCallback, функция состоит в том, чтобы позволить некоторым операциям и методам следовать за обновлением статуса для выполнения.

а такжеuseMemoВ сравнении.

  • Это можно рассматривать просто как,useMemo(() => Fn,deps)эквивалентноuseCallback(Fn,deps)

разница:

  • useCallbackОн оптимизирует переданную функцию обратного вызова и возвращает функцию;useMemoВозвращаемое значение может быть чем угодно, функциями, объектами и т.д.

Тот же пункт:

  • По способу использования,useMemoа такжеuseCallbackтакой же. Получает функцию в качестве параметра, а также принимает второй параметр в виде списка зависимостей

5.1 Почему?useCallbackто, что кэшируется, является функцией (важное отличие)

  • useCallbackХотя сuseMemoАналогично, но возвращает и кэширует функцию, сравните пример кода ниже. Давайте поговорим о сравнении ①②③ трех случаев (вы можете скопировать код, а затем прокомментировать ①②③ сравнение кода)

    • В случае ① он будет напечатан только один раз.获取双倍Num1, который является первым визуализированным отпечатком, а затем щелкнитеdivизменение площадиageЗначение не имеет значения, поэтому оно не будет выполнено. потому чтоgetDoubleNumуже полученоuseMemoЗначение, возвращаемое после выполнения переданной функции, после его получения кэшируется.

    • В случае ② первая визуализация будет напечатана один раз.获取双倍Num1, то каждый щелчок будет печатать获取双倍Num1,Почему это? не говоряuseCallbackЕсть ли функция кэширования? Это связано с тем, что, как мы упоминали ранее,useCallbackТо, что возвращается, является функцией. потому чтоuseCallbackФункция в определена в текущем компоненте.Если компонент повторно отображается, он, естественно, повторно отображается.Некоторые студенты сказали это, но это не означает, что он кэширует функцию. Затем вы можете сначала посмотреть на зависимости ③ как[]ситуации, тогда вы поймете.Поэтому он не подходит для сценариев со сложной логикой расчета.useCallbackКешировать, потому что входящее содержимое функции будет выполняться непрерывно.

    • Когда имеет место ③, мы объединяем отмеченный код в ②③,setХранить можно только уникальные значения, наблюдаем за напечатаннымsetдлина

      • когдаuseCallbackЗависимость пуста[], мы нажимаем несколько раз подрядdivплощадь, хотяuseCallbackСодержимое in будет выполняться непрерывно, но мы можем видеть напечатанноеsetДлина всегда была2, потому что он продолжает добавлять одну и ту же функцию кset,такsetдлина
      • и когдаuseCallbackзависит от[num], мы нажимаем несколько раз подрядdivобласть, вы можете увидеть печатнуюsetпостоянно накапливается,1、2、3、4、5、6.... потому чтоnumменяется, поэтому каждый раз, когда кэшированная функция является новой функцией, поэтому добавьтеsetФункции не совпадают, поэтомуsetТочки длины добавляются по одной
    const set = new Set()
    export default function StateFunction () {
        const [num, setNum] = useState(1)
        const [age, setAge] = useState(18)
    
        const getDoubleNum = useMemo( () => {
            console.log(`获取双倍Num${num}`)
            return 2 * num  //	①假设为复杂计算逻辑
        },[] )
    
        const getDoubleNum = useCallback( () => {
            console.log(`获取双倍Num${num}`)
            return 2 * num  //	②假设为复杂计算逻辑
        },[] )
    
        set.add(getDoubleNum())  //	③注意set打印的长度变化(设置Callback的依赖为[]、[num]进行对比)
        console.log('set.size:',set.size)
    
        return (
            <div onClick={ () => { setNum( num => num+1 ) }  }>
                <br></br>
                这是一个函数式组件————num:{  getDoubleNum } //①useMemo情况下
                这是一个函数式组件————num:{  getDoubleNum() } //②useCallback情况下
                <br></br>
                age的值为————{ age }
                <br></br>
            </div>
        )
    }
    

5.2 Применимые сценарии UseCallback

Проблема рендеринга параметров родительских и дочерних компонентов может быть оптимизирована. Проще говоря,Если входящая функция родительского компонента не обновляется, она не вызовет повторное выполнение функции дочернего компонента.

  • Обычно при обновлении родительского компонента обновляется и дочерний компонент. Но если содержимое родительского компонента, переданного в дочерний компонент, остается неизменным, то некоторые операции дочернего компонента (некоторые операцииОтносится к операциям, которые необходимо выполнять синхронно с изменениями входящего контента.) не нужен, это повлияет на производительность страницы, поэтому мы можем оптимизировать эту ситуацию.

  • Например код, мы будемgetDoubleNumПередайте дочерний компонент, щелкните в это времяdivИзмененная площадьnumЗначение, мы используем родительский компонентuseCallbackс подкомпонентамиuseEffectоптимизировать, только когда родительский компонентnumИзменения, которые приводят к тому, что входящий дочерний компонентgetDoubleNumКогда изменение будет внесено, мы выполним некоторые операции, которые необходимо обновить в подкомпоненте (то есть код в аннотации), чтобы избежать повторного выполнения некоторых ненужных операций обновления подкомпонента и повлиять на производительность. страницы.

function Parent () {

    const [num, setNum] = useState(1)
    const [age, setAge] = useState(18)

    const getDoubleNum = useCallback( () => {
        console.log(`获取双倍Num${num}`)
        return 2 * num
    },[num] )

    return (
        <div onClick={ () => {setNum( num => num+1 )} }>
            这是一个函数式组件————num:{  getDoubleNum() }
            <br></br>
            age的值为————age:{ age }
            <br></br>
            set.size:{set.size}
            <Child callback={ getDoubleNum() }></Child>
        </div>
    )
}

function Child(props) {
    useEffect( () => {
        console.log('callback更新了') //这里代表的是需要跟随传入内容的改变而同步进行的操作
    },[props.callback])

    return (
        <div>
            子组件的getDoubleNum{props.callback}
        </div>
    )
}

5.3 Резюме и справочные подробные статьи

Краткое резюме оценки сценария использования:

  • В случае, если дочерний компонент не нуждается в значениях и функциях родительского компонента, вам нужно только использоватьmemoФункция оборачивает дочерний компонент
  • Если есть функция, переданная дочернему компоненту, используйтеuseCallback
  • При кэшировании сложной логики вычислений в компоненте, который должен возвращать значение, используйтеuseMemo
  • Если есть значение для передачи дочернему компоненту, используйтеuseMemo

Обратитесь к подробной статье:

6 useRef

Проще говоряuseRefдолжен вернуть индекс дочернего элемента, этот индекс остается неизменным на протяжении всего жизненного цикла. Функция заключается в сохранении данных в течение длительного времени. Меры предосторожности, сохраненный объект изменяется без уведомления. Изменения свойств не повторяются

  • НеиспользованныйuseRef, если у нас есть такое требование, как показано ниже, нам нужно очистить таймер, когда значение самоинкремента таймера достигает предельного условия, как показано в следующем коде. В настоящее время следующий код фактически не может выполнить данные требования, когдаnumбольше, чем10После этого вас ждет непрерывная печать大于10了,清除定时器, но на самом деле таймер не сбрасывается, поэтому эти два содержимого печати будут выполняться все время, но вы обнаружите, что напечатанноеtimerпоказыватьundefined,Почему это? Потому что каждый раз, когда мы визуализируем, мы передаемsetIntervalвернулсяtimer,timerОн также обновляется и теряетсяtimerЭти данные делают невозможным точную очистку таймера, который необходимо очистить.
    const [num, setNum] = useState(0)
    
    let timer
    useEffect( () => {
        timer = setInterval( () => {
            setNum( num => num+1 )
        },400 )
    },[] )
    
    useEffect( () => {
        if(num > 10){
            console.log('大于10了,清除定时器')
            console.log('timer:',timer)
            //  因为每一个timer都是独立render的,所以获取不到
            clearTimeout(timer)
        }
    },[num] )
    
    return (
        <div>
            这是一个函数式组件————num:{  num }
        </div>
    )
    
  • использоватьuseRefПосле этого код выглядит следующим образом. Мы видим, чтоnumувеличить до11后просто напечатал один раз大于10了,清除定时器так же какref.current 1, а затем прекратите увеличение, поскольку таймер сброшен.refявляется объектом,ref.currentСохраняет весь жизненный цикл таймераidзначение, поэтому, когда таймер очищается, таймер может быть точно очищен
    • сохраняет значение, которое сохраняется на протяжении всей его жизни
    const [num, setNum] = useState(0)
    
    const ref = useRef()
    useEffect( () => {
        ref.current = setInterval( () => {
            setNum( num => num+1 )
        },400 )
        // ref.current = '111'
    },[] )
    
    useEffect( () => {
        if(num > 10){
            console.log('大于10了,清除定时器')
            console.log('ref.current',ref.current)
            clearTimeout(ref.current)
        }
    },[num] )
    
    return (
        <div>
            这是一个函数式组件————num:{  num }
        </div>
    )
    
    • переназначатьref.currentАктивно не запускает повторный рендеринг страницы. Когда мы изменим код на следующий, мы напечатаем открытие в консоли.ref.currentЗначение печатается как111, но вид страницы все еще пусто, потому чтоrefСохраненные объекты изменяются, активно не уведомляются, изменения атрибутов не отображаются
    const [num, setNum] = useState(0)
    
    const ref = useRef()
    useEffect( () => {
        ref.current = '111'
        console.log('ref.current',ref.current)
    },[] )
    
    return (
        <div>
        	  这是ref.current的值——ref.current:{ ref.current }
            <br></br>
            这是一个函数式组件————num:{  num }
        </div>
    )
    

7 useContext

useContextЭто позволяет дочерним компонентам совместно использовать состояние, переданное родительским компонентом. С точки зрения непрофессионала, функция состоит в том, чтобы отклоняться от подкомпонентов.

  • НеиспользованныйuseContext, у нас есть следующий сценарий, наш родительский компонент передал значение различным дочерним компонентам, код, приведенный в примере,2такие подкомпоненты, но что, если мне нужно добавить слишком много подкомпонентов? Его не всегда можно добавлять и записывать один за другим, и если одно и то же имя переменной передается в изменениях, оно должно быть изменено одно за другим, поэтому мы можем использоватьuseContextоптимизировать код
    function StateFunction () {
        const [num, setNum] = useState(1)
    
        return (
            <div>
                <button onClick={ ()=> setNum(num => num+1) }>增加num的值+1</button>
                <br></br>
                这是一个函数式组件——num:{  num }
                <Item1 num={num}></Item1>
                <Item2 num={num}></Item2>
                //	......
            </div>
        )
    }
    
    function Item1 (props) {
        return (
            <div>
                子组件1 num:{ props.num }
            </div>
        )
    }
    
    function Item2 (props) {
        return (
            <div>
                子组件2 num:{ props.num }
            </div>
        )
    }
    
  • использоватьuseContextПосле оптимизации код выглядит следующим образом, так что нам нужно использовать только в дочерних компонентахuseContext(Context句柄)Чтобы получить данные, вам не нужно обращать внимание на определение дочернего компонента в родительском компоненте при добавлении однотипного дочернего компонента.propsПередайте значение, используйте метод следующим образом
    • нужно представитьuseContetx,createContextдва содержания
    • пройти черезcreateContextСоздать дескриптор контекста
    • Context.Providerдля определения объема обмена данными
    • пройти черезvalueраспространять контент
    • В дочернем компоненте передатьuseContext(Context句柄)получить данные
    • Меры предосторожности, данные верхнего слоя изменятся, это обязательно вызовет повторный рендеринг (нажмитеbuttonКнопка запускает родительский компонент для обновления входящегоnumзначение для повторного рендеринга дочерних компонентов)
    const Context = createContext(null)
    
    function StateFunction () {
        const [num, setNum] = useState(1)
    
        return (
            <div>
                <button onClick={ ()=> setNum(num => num+1) }>增加num的值+1</button>
                <br></br>
                这是一个函数式组件——num:{  num }
                <Context.Provider value={num}>
                    <Item3></Item3>
                    <Item4></Item4>
                </Context.Provider>
            </div>
        )
    }
    
    function Item3 () {
        const num = useContext(Context)
    
        return (
            <div>
                子组件3: { num }
            </div>
        )
    }
    
    function Item4 () {
        const num = useContext(Context)
    
        return (
            <div>
                子组件4: { num+2 }
            </div>
        )
    }
    

8 useReducer

Раньше его можно было использовать только в компонентах класса.Redux, теперь мы можем пройтиuseReducerИспользование в функциональных компонентахRedux. Роль состоит в том, чтобы получить желаемое состояние с помощью инструмента управления состоянием.

  • как использоватьuseReducer.ReduxНеобходимый контент — это складstoreи менеджерыreducer. а такжеuseReducerТо же самое, вам нужно создать хранилище данныхstoreи менеджерыreducer, то есть в комментарии примера кода. Тогда мы можем пройтиОпределите массив, чтобы получить состояние и изменить состояние действия, которое необходимо передать при запуске действия.typeВведите суждение для срабатыванияreducerКакие действия, а затем изменить данные. Следует отметить, что вreducerсерединаreturnобъект, необходимоstateДеструктурирование, иначе государство остается сnumстоило того
    const store = {
        age:18,
        num:1
    }	//	数据仓库
    
    const reducer = (state, action) => {
        switch(action.type){
            case 'add':
                return {
                    ...state,
                    num: action.num+1
                }
    
            default:
                return {
                    ...state
                }
        }
    } //	管理者
    
    function StateFunction () {
        const [state,dispacth] = useReducer(reducer,store)  //	①
    
        return (
            <div>
                <button onClick={ () => {
                    dispacth({
                        type: 'add',
                        num: state.num
                    })
                } }>
                    增加num的值+1
                </button>
                <br></br>
                这是一个函数式组件——num:{  state.num }
            </div>
        )
    }
    

Суммировать

Вы закончили? Я не знаю, получили ли вы что-нибудь после прочтения.Эта статья анализируется с точки зрения уровня использования и некоторых примеров ежедневного применения, и здесь нет глубокого анализа. Если вы хотите узнать больше об этихHooks, рекомендуется посмотреть официальный исходный код. прикрепить мое исследованиеDemoсклад,Обучающий репозиторий React Hooks

напиши в конце

Если вы считаете, что я пишу неплохо, вы можете поставить мне лайк ^^, если что-то не так или плохо, пожалуйста, прокомментируйте и укажите на это, чтобы я мог исправить