hook的使用总结

hook简介

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。践行函数式编程的方式,在函数组件中使用,获得class编写的特性。

useState和useReducer

useState

  • useState给一个state赋初始值,并且返回一个数组,一个用来读取state的值,一个用来设置state的值。
  • useState声明的state在发生变化的时候,会触发组件的更新。
  • setState更新state是异步更新策略,参数有两种,一种要更新的值,第二种是一个更新的函数,返回要更新的值。
  • setState不会进行合并更新,只会全量更新,所以参数或回调函数值应该要更新的值。
const [state, setState] = useState(10);
// 赋值修改
setState(20) // 此方法就是将state修改为20
// 函数修改
setState(current => {
    // current 是当前state的值
    return current + 20; // 修改state的值为40
   // return state + 20; // 这样也是可以的
})

useReducer

useState 的替代方案。它接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法。(如果你熟悉 Redux 的话,就已经知道它如何工作了。)

用法简介

const [state, dispatch] = useReducer(reducer, initialState, init);
  • reducer是一个函数,该函数接受两个参数,一个是state一个是action, 是修改state值得函数。
  • initialState 初始值
  • init一个函数,用于初始化时调用的函数,返回的就是初始化的state
  • useReducer返回一个状态statedispatch,state是返回状态的值,dispatch是可以发布事件来更新state的函数,修改state值得韩式就是reducer。

指定初始值

function counter = () => {
    // 声明count,返回一个count 和 dispatch
    const [count, dispatch] = useReducer((state, action) => {
        // state 就是当前count的值
        // action 就是dispatch函数的参数,可以为任何类型的数据
        if (action === 'add') {
            return state + 1;
        } else {
            return state - 1;
        }
    }, 0) // 默认初始值为0

    return (
        

{count}

{* 调用dispatch来更新count *}
) }

惰性初始化

如果state初始化时需要有重置的操作或者state初始化的值十分复杂,都可以使用useReducer的第三个参数init

const initState = 10;
// 重置时会走该函数
const init = initState => {
    return initState;
}

function counter = () => {
    // 声明count,返回一个count 和 dispatch
    const [count, dispatch] = useReducer((state, action) => {
        // state 就是当前count的值
        // action 就是dispatch函数的参数,可以为任何类型的数据
        if (action === 'add') {
            return state + 1;
        } else if(action === 'sub') {
            return state - 1;
        } else if (action === 'reset') {
            return init(initState);
        }
    }, initState, init)

    return (
        

{count}

{* 调用dispatch来更新count *}
) }

注意

  • useReducer返回的state和当前的一样时,是不会重新渲染该组件的,因为react使用Object.js来比较state。
  • 对于state有比较复杂的赋值操作时建议使用useReducer来声明和处理。

useEffect 和 useLayoutEffect

useEffect

  • useEffect可以执行副作用的操作
  • useEffect有两个参数,一个回调函数,一个数组类型变量(这里面的值必须是依赖项,就是使用useState等声明的变量,可以触发组件更新的变量)
  • useEffect会在每次render的时候都执行,可以通过参数控制只在初始化时执行、某些数据变化时执行
  • 相当于class组件的声明周期componentDidMount(组件渲染后执行)和componentDidUpdate(组件更新后执行)
  • useEffect是一个回调函数,如果返回一个函数时,则会在componentWillUnmount(组件销毁)时执行

只在初始化时执行

在第二个参数中传递[]空数组,则只在初始化时调用

useEffect(() => {
    // 初始化时获取list数据
    getList();
}, [])

在初始化和render更新时执行

第二个参数不穿时,会在初始化和更新时执行

useEffect(() => {
    getList();
})

在某些数据变化时执行

// 在count数据变化的时候执行
useEffect(() => {
    getList();
}, [count]) // 数组中可以放许多的变量,在这些数据变化时都会执行

useLayoutEffect

  • 当需要处理dom时,使用useEffect会导致闪屏问题
  • useLayoutEffect会在DOM更新完成后立即执行,在浏览器进行回执之前运行
  • 回阻塞浏览器的绘制

useContext

介绍

  • 接受一个context(React.createContext的返回值)对象
  • useContext帮助我们跨越组件层级直接传递变量,实现共享,解决了组件之间传值的问题。
  • context对象提供provider属性将数据可以通过垮组件访问,通过value将值传给子组件
  • useContext获取的数据是跟随数据源里的数据的变化而变化的。
const value = useContext(MyContext);

使用

// 父组件 parent.js
import React, { useState, createContext } from 'react'
import Children from './children.js'

const Parent = () => {
    const [count, setCount] = useState(10);
    const CountContext = createContext();
    
    return (
        <>
            
                
            
            

{ count }

) } // 子组件 children.js import React, { useContext } from 'react' const Children = props => { // 这里的countContext是从组件传递过来的 // 也可以把createCount单独放到模块里面进行引用 // 引用模式应该比props好,可以适应组件嵌套的问题 const { countContext } = props; // 这里的数据是随着父组件中的count数据变化而变化的 const countData = useContext(countContext); return (

{ countData.count }

) }

useRef 与 useImperativeHandle

useRef

const refContainer = useRef(initialValue);
  • useRef返回一个可变的ref对象,其.current属性就是被初始化传入的参数。
  • useRef中的值发生变化不会触发组件的更新
  • useRef可以用来保存任何可变值。
  • 绑定到原生html上面可以获取该标签的方法,绑定到自定义组件上,则不要通过useImperativeHandle将部分方法和属性暴露出来。
  • useImperativeHandle可以在使用ref的时候自定义暴露给父组件的实例值和方法,需要和forwardRef一起使用

useImperativeHandle

useImperativeHandle(ref, createHandle, [deps])
  • ref:定义 current 对象的 ref createHandle:一个函数,返回值是一个对象,即这个 ref 的 current对象
  • [deps]:即依赖列表,当监听的依赖发生变,useImperativeHandle 才会重新将子组件的实例属性输出到父组件
  • ref 的 current 属性上,如果为空数组,则不会重新输出。

实例

// 父组件 parent.js
import React, {useRef} from 'react'
import Children from './children'

const Parent = () => {
    const childRef = useRef();
    
    return (
        <>
            
            
        
    )
}
// children.js
import React, {useState, useImperativeHandle, forwardRef} from 'react'

// 第二个参数才是ref,第一个是props
const Children = (props, ref) => {
    const [count, setCount] = useState(1)
    
    useImperativeHandle(ref, () => {
        addCount: setCount
    })
    
    return (
        

{count}

) } // 需要使用forwardRef进行一次转发 export default forwardRef(Children);

useCallback和useMemo

  • 都是用于数据缓存的方法
  • 都可以根据依赖项进行刷新
  • 主要是用在不需要随着组件更新而更新的情况时,用于优化部分复杂函数更新问题
  • useCallback返回函数,并不调用他们
  • useMemo 调用函数,返回执行的结果

用法

// useCallback 返回一个函数
const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);
// useMemo  执行函数,返回执行的结果
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

例子

// parent.js
import React, {useState, useCallback, useMemo} from 'react'
import ChildrenComponent from './Children.js'

const Parent = () => {
    const [count, setCount] = useState(10)
    const [num, setNum] = useState(10)
    
    // 只有count变化的时候countName才会更新,可以作为优化部分
    const countName = useMemo(() => `年龄:${count}`, [count]);
    
    // 这样,只有在num更新的时候,children组件才会更新
    const setDataNum = useCallback(() => setNum(num + 10), [num]);
    
    return (
        

{countName}

NUM {num}

) } // children.js import React from 'react'; const Children = ({setData}) => { return ( ) } export React.memo(Children)

你可能感兴趣的:(hook的使用总结)