предисловие
Я давно не писал статьи, подытожу и запишу восемь вещей, которые я обычно использую или которые, как мне кажется, мне следует освоить.React Hooks
.如果算上自定义Hooks
, должно быть девять, но эта статья не будет расширяться. Я только что узнал, прежде чем пришел в NetEaseReact
Framework, я просмотрел проект компании в течение дня, а затем обнаружил, что мне нужно взглянуть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 }) }
-
Контраст с компонентами класса: Если он размещен в компоненте класса, это окончательное значение, измененное во время печати настройки.Эквивалентный код в компоненте класса выглядит следующим образом (дан только код ключа). Что значит напечатать окончательное значение, измененное за установленное время? Если вы установите 3000 миллисекунд, отсчет времени начнется в момент окончания рендеринга, а если вы нажмете три раза подряд в течение 3000 миллисекунд, вы в итоге напечатаете 4 раза.
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
Обратитесь к подробной статье:
- Вышеизложенное является некоторыми из моих личных представлений в сочетании с данными.Если вы думаете, что то, что я сказал, все еще неясно, вы можете обратиться к следующим двум хорошо написанным статьям, которые могут быть более ясными.
- Руководство по использованию useMemo и useCallback
- Подробное объяснение useCallback и 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
напиши в конце
Если вы считаете, что я пишу неплохо, вы можете поставить мне лайк ^^, если что-то не так или плохо, пожалуйста, прокомментируйте и укажите на это, чтобы я мог исправить