Наконец-то разобрались с React Hooks! ! ! ! !

React.js

суммировать!

Изучение записей из трех измерений:

  1. почему 🤔️
  2. Как пользоваться 🔨
  3. Очки знаний⛽️

useState

Зачем использовать useState?

useStateВнешний вид: используйте класс в функциональных компонентахsetState, Стимулировать!

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

Как использовать useState?

const [name, setName] = useState('rose')

useState наступает на очки знаний ямы

😄1. Ключевые моменты:useState的初始值,只在第一次有效

В то время я не воспринимал это всерьез, пока не столкнулся с ямой...

🌰2. Например:

Когда я нажал кнопку изменить значение имени, я обнаружил, что в дочернем компоненте оно было получено, но не прошлоuseStateПрисвоить имя!

Вывод: Практикуйте тестовые очки знаний! 😭

const Child = memo(({data}) =>{
    console.log('child render...', data)
    const [name, setName] = useState(data)
    return (
        <div>
            <div>child</div>
            <div>{name} --- {data}</div>
        </div>
    );
})

const Hook =()=>{
    console.log('Hook render...')
    const [count, setCount] = useState(0)
    const [name, setName] = useState('rose')

    return(
        <div>
            <div>
                {count}
            </div>
            <button onClick={()=>setCount(count+1)}>update count </button>
            <button onClick={()=>setName('jack')}>update name </button>
            <Child data={name}/>
        </div>
    )
}

useEffect

Зачем использовать useEffect?

Внешний вид useEffect таков: использование функции жизненного цикла класса в функциональном компоненте или сочетание всех функций! Стимулировать!

Как использовать useEffect?

useEffect(()=>{
    ...
})

Сбор очков знаний useEffect

😄1. componentDidMount, который используется только в первый раз, можно использовать для запроса асинхронных данных...,

В конце useEffect добавление [] означает, что он выполняется только в первый раз.

useEffect(()=>{
    const users = 获取全国人民的信息()
},[])

😄2.Используется для замены willUpdate и других жизненных функций, которые будут выполняться каждый раз при рендере

В конце useEffect, если вы не добавите [], это означает, что будет выполняться каждый рендеринг

useEffect(()=>{
    const users = 每次都获取全国人民的信息()
})

😄3. Выполнение каждого рендера кажется немного дорогим, поэтому:

В конце useEffect добавляем [], а добавленное поле в [] означает, что это поле изменено, и мой эффект выполняется.

useEffect(() => {
    const users = (name改变了我才获取全国人民的信息())
},[name])

😄4. Что делать, если я хочу разделить имя и возраст:

Можно написать несколько useEffects

useEffect(() => {
    const users = (name改变了我才获取全国人民的name信息())
},[name])

useEffect(() => {
    const users = (name改变了我才获取全国人民的age信息())
},[age])

😄5.Если мы подписались на что-то раньше, и окончательно отменили подписку в жизненном цикле willUnMount, как этого можно добиться с помощью useEffect:

Вы можете отписаться в возврате эффекта

useEffect(() => {
    const subscription = 订阅全国人民吃饭的情报!
    return () => {
        取消订阅全国人民吃饭的情报!
    }
},[])

Зачем отписываться?

Все мы знаем, что после рендеринга будет выполняться re-useEffect.Если в useEffect есть setInterval... Тогда каждый раз при рендеринге повторное выполнение useEffect будет создавать еще один setInterval, и тогда будет путаница... Можно вернуть следующий случай удалить содержимое

useEffect(() => {
        console.log('use effect...',count)
        const timer = setInterval(() => setCount(count +1), 1000)
        return ()=> clearInterval(timer)
    })

😄6.Некоторые секретные правила UseEffect:

1. Значение состояния, используемое в useEffect, фиксируется внутри useEffect и не будет изменено, пока useEffect не обновит и не зафиксирует значение состояния.

 const [count, setCount] = useState(0)
    useEffect(() => {
        console.log('use effect...',count)
        const timer = setInterval(() => {
            console.log('timer...count:', count)
            setCount(count + 1)
        }, 1000)
        return ()=> clearInterval(timer)
    },[])
    

2.useEffect нельзя судить о пакете

const [count, setCount] = useState(0)
if(2 < 5){
   useEffect(() => {
        console.log('use effect...',count)
        const timer = setInterval(() => setCount(count +1), 1000)
        return ()=> clearInterval(timer)
    }) 
}

3.useEffect нельзя прервать

const [count, setCount] = useState(0)
useEffect(...)

return // 函数提前结束了

useEffect(...)
}

Конкретная причина связана с правилами генерации и выполнения useEffect: см. документацию!

useRef

Зачем использовать useRef?

упоминалось ранее:

Значение состояния, используемое в useEffect, фиксируется внутри useEffect и не будет изменено, если только useEffect не обновит и не зафиксирует значение состояния.

 const [count, setCount] = useState(0)
    useEffect(() => {
        console.log('use effect...',count)
        const timer = setInterval(() => {
            console.log('timer...count:', count)
            setCount(count + 1)
        }, 1000)
        return ()=> clearInterval(timer)
    },[])
    

useEffectЗначение состояния внутри фиксировано, есть способ решить эту проблему, просто используйтеuseRef, можно понимать какuseRefРоль:

Это эквивалентно глобальной области, одна изменяется, а другая обновляется...

Как использовать useRef?

const countRef = useRef(0)

Коллекция очков знаний useRef

😄 1. Эквивалент глобальной области видимости, одна модифицируется, а другая обновляется...

 const [count, setCount] = useState(0)
 const countRef = useRef(0)
useEffect(() => {
    console.log('use effect...',count)
    const timer = setInterval(() => {
        console.log('timer...count:', countRef.current)
        setCount(++countRef.current)
    }, 1000)
    return ()=> clearInterval(timer)
},[])

😄 2. Общая операция, используемая для работы с домом

const btnRef = useRef(null)

click me

Живи и учись, не забудь отвязать событие! return ()=> btnRef.current.removeEventListener('щелчок',onClick, false)

const Hook =()=>{
    const [count, setCount] = useState(0)
    const btnRef = useRef(null)

    useEffect(() => {
        console.log('use effect...')
        const onClick = ()=>{
            setCount(count+1)
        }
        btnRef.current.addEventListener('click',onClick, false)
        return ()=> btnRef.current.removeEventListener('click',onClick, false)
    },[count])

    return(
        <div>
            <div>
                {count}
            </div>
            <button ref={btnRef}>click me </button>
        </div>
    )
}

useMemo

Зачем использовать useMemo?

Например 🌰:

const Child = memo(({data}) =>{
    console.log('child render...', data.name)
    return (
        <div>
            <div>child</div>
            <div>{data.name}</div>
        </div>
    );
})

const Hook =()=>{
    console.log('Hook render...')
    const [count, setCount] = useState(0)
    const [name, setName] = useState('rose')

    const data = {
        name
    }

    return(
        <div>
            <div>
                {count}
            </div>
            <button onClick={()=>setCount(count+1)}>update count </button>
            <Child data={data}/>
        </div>
    )
}

Когда мы нажимаем кнопку, чтобы обновить счетчик, компонент Effect будет отображаться.После рендеринга выполняется эта строка кода:

   const data = {
        name
    }

Эта строка кода сгенерирует объект с новым адресом памяти, так что даже с дочерним компонентом памятки он будет перерендерен, хотя значение, используемое дочерним элементом, в итоге не изменилось!

Таким образом, рендеринг является излишним, и это похоже на пустую трату производительности! тогдаuseMemoОн пришел как человек с возможностью временного хранения.

Как использовать useMemo?

  const data = useMemo(()=>{
        return {
            name
        }
    },[name])

, сначала он будет основан на[name]Судите о значении имени внутри, потому чтоuseMemoВ качестве возможности временного хранения результат по фамилии временно сохраняется.

В итоге, сравнив фамилию, мы обнаружили, что значение имени не изменилось! Тогда на этот раз данные не будут переназначены новому объекту!

Без новых объектов не будет новых адресов памяти, поэтому Child не будет перерисовываться!

const Child = memo(({data}) =>{
    console.log('child render...', data.name)
    return (
        <div>
            <div>child</div>
            <div>{data.name}</div>
        </div>
    );
})

const Hook =()=>{
    console.log('Hook render...')
    const [count, setCount] = useState(0)
    const [name, setName] = useState('rose')

   const data = useMemo(()=>{
        return {
            name
        }
    },[name])
    
    return(
        <div>
            <div>
                {count}
            </div>
            <button onClick={()=>setCount(count+1)}>update count </button>
            <Child data={data}/>
        </div>
    )
}

Коллекция очков знаний useMemo

useMemoНа первый взгляд мне кажется, что с памяткой какие-то медовые отношения, потому что есть памятка...

😄 1. Во-первых,memoИспользование:函数组件里面的PureComponent

Однако, если функциональный компонент обернут в React.memo и имеет в своей реализации хук useState или useContext, он все равно будет повторно отображаться при изменении контекста.

😄 2. И,memoЭто поверхностное сравнение, что означает, что объект сравнивает только адрес памяти.Пока ваш адрес памяти не изменится, независимо от постоянно меняющегося значения в вашем объекте, рендеринг не будет запущен.

😄 3. Наконец,useMemoЭффект, тогдаuseMemoВ качестве временной способности хранения здесь идет:

useCallback

Зачем использовать useCallback?

useMemo решает проблему кэширования значений, а как насчет функций?

Следующее 🌰 заключается в том, что при нажатии кнопки счетчика рендеринг компонента «Эффект» обнаруживает:

   const onChange=(e)=>{
        setText(e.target.value)
   }
    

Затем регенерируйтеonChangeФункция назначается дочернему компоненту, неглубокое сравнение не выполняется, и дочерний компонент успешно выполняет повторную визуализацию, хотя дочерний компонент ничего не делает!

const Child = memo(({data, onChange}) =>{
    console.log('child render...')
    return (
        <div>
            <div>child</div>
            <div>{data}</div>
            <input type="text" onChange={onChange}/>
        </div>
    );
})

const Hook =()=>{
    console.log('Hook render...')
    const [count, setCount] = useState(0)
    const [name, setName] = useState('rose')
    const [text, setText] = useState('')

   const onChange=(e)=>{
        setText(e.target.value)
   }
    
    return(
        <div>
            <div>count: {count}</div>
            <div>text : {text}</div>
            <button onClick={()=>setCount(count + 1)}>count + 1</button>
            <Child data={name} onChange={onChange}/>
        </div>
    )
}

Как использовать useCallback?

   const onChange = useCallback((e)=>{
        setText(e.target.value)
   },[])

Коллекция очков знаний useCallback

😄1.useMemoиuseCallbackАналогично, у всех есть функция кэширования. Существенной разницей может быть:

useMemo — это кешированное значение

useCallback — это функция кеша

😄2.Зависимости нет, добавление пустой зависимости - это пустой массив!

useReducer

Зачем использовать useReducer?

Как следует из названия,useReducerЭто редуктор в классе

Как использовать useReducer?

Например 🌰:

const reducer =(state = 0, {type})=>{
    switch (type) {
        case "add":
            return state+1
        case 'delete':
            return state-1
        default:
            return state;
    }
}

const Hook =()=>{
    const [count, dispatch] = useReducer(reducer, 0)
    return(
        <div>
           count:{count}
           <button onClick={()=> dispatch({type:'add'})}>add</button>
            <button onClick={()=> dispatch({type:'delete'})}>delete</button>
        </div>
    )
}

export default Hook

Коллекция очков знаний useReducer

Пока ничего особенного... 😼

useContext

Зачем использовать useContext?

useContextЭто контекст в классе.

Как использовать useContext?

import React, {useContext, useReducer} from 'react'

const reducer = (state = 0, {type}) => {
    switch (type) {
        case "add":
            return state + 1
        case 'delete':
            return state - 1
        default:
            return state;
    }
}
const Context = React.createContext(null);

const Child = () => {
    const [count, dispatch] = useContext(Context)
    return (
        <div>
            <div>child...{count}</div>
            <button onClick={() => dispatch({type: 'add'})}>child add</button>
            <button onClick={() => dispatch({type: 'delete'})}>child delete</button>
        </div>

    )
}

const Hook = () => {
    const [count, dispatch] = useReducer(reducer, 10)
    return (
        <Context.Provider value={[count, dispatch]}>
            <div>
                <div>mom ... {count}</div>
                <Child/>
                <button onClick={() => dispatch({type: 'add'})}>mom add</button>
                <button onClick={() => dispatch({type: 'delete'})}>mom delete</button>
            </div>
        </Context.Provider>
    )
}

export default Hook

Коллекция точек знаний useContext

Пока ничего особенного... 😼

Крючки на заказ!

Настройте хук, который прислушивается к ширине и высоте окна при изменении размера

import {useEffect, useState} from "react";

export const useWindowSize = () => {
    const [width, setWidth] = useState()
    const [height, setHeight] = useState()

    useEffect(() => {
        const {clientWidth, clientHeight} = document.documentElement
        setWidth(clientWidth)
        setHeight(clientHeight)
    }, [])

    useEffect(() => {
        const handleWindowSize = () =>{
            const {clientWidth, clientHeight} = document.documentElement
            setWidth(clientWidth)
            setHeight(clientHeight)
        };

        window.addEventListener('resize', handleWindowSize, false)

        return () => {
            window.removeEventListener('resize',handleWindowSize, false)
        }
    })

    return [width, height]
}

как пользоваться:

const [width, height] = useWindowSize()

Наконец