React Hooks -useReducer/useLayoutEffect/useImperativeHandle详解(3)

645 阅读2分钟

这是我参与更文挑战的第23天,活动详情查看: 更文挑战

1, useImperativeHandle

1 ,用法

useImperativeHandle(ref, createHandle, [deps])

useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值。在大多数情况下,应当避免使用 ref 这样的命令式代码。useImperativeHandle 应当与 forwardRef 一起使用:

useImperativeHandle(ref(传递来的), ()=>{}, [])

2, 举例

import './App.css';
import React , { useRef, forwardRef , useImperativeHandle, useState } from 'react'


const ForWard = forwardRef((props, ref) => {
    return (
        <>
          <h2 ref={ref}>12345</h2>
          <h2>JamieDawn</h2>
        </>
    )
})
const Imperative = forwardRef((props, ref) => {
    const inputRef = useRef(null)
    const [count, setCount] = useState(0)
    const [num, setNum] = useState(0)
    useImperativeHandle(ref, ()=> {
        console.log('useImperativeHandle')
        return ({
            name: 'zlm',
            focus: ()=> {
               inputRef.current.focus()
            }
        })
    }, [num]) 
    return (
        <>
        <h2>count{count}</h2>
        <h2>num{num}</h2>
        <input type="text" ref={inputRef} />
        <button onClick={()=>{setCount(count + 1)}}>setCount</button>
        <button onClick={()=>{setNum(num + 1)}}>setNum</button>
        </>
    )
})
function App() {
    const hRef = useRef(null)    
    const el = useRef(null)

  return (
    <>
      <ForWard ref={hRef}/>
      <Imperative ref={el} />
      <button onClick={()=> {
          console.log(hRef.current)
      }}>获取forWardRef</button>
      <button onClick={()=> {
          console.log(el.current)
          el.current.focus()
      }}>获取Imperative</button>
     </>
  );
}

export default App;

2, useLayoutEffect

1, 用法

其函数签名与 useEffect 相同,但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。

尽可能使用标准的 useEffect 以避免阻塞视觉更新。

注意: useLayoutEffectuseEffect 不同之处: 执行的时间不同,useEffect是在componentDidMount以后执行的,useLayoutEffect是在浏览器执行绘制之前执行,会阻塞组件挂载,慎用

2, 举例

import './App.css';
import React , { useEffect, useLayoutEffect } from 'react'



function App() {
    useEffect(() => {
        console.log('useEffect')
        return ()=> {
            console.log('useEffect-return')
        }
    })
    useLayoutEffect(() => {
        console.log('useLayoutEffect')
        return () => {
            return () => {
                console.log('useLayoutEffect-return')
            }
        }
    })
  return (
    <>
      <h2>useLayoutEffect</h2>
     </>
  );
}

export default App;

3, 执行

首先: useLayoutEffect 执行
然后: useEffect 执行

组件在消毁或者改变状态的时候
首先: useLayoutEffect-return 执行
然后: useLayoutEffect  执行
接着: useEffect-return 执行
最后: useEffect 执行

3, useReducer

1, 用法

const [state, dispatch] = useReducer(reducer, initialArg, init);

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

在某些场景下,useReducer 会比 useState 更适用,例如 state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 等。并且,使用 useReducer 还能给那些会触发深更新的组件做性能优

化,因为你可以向子组件传递 dispatch 而不是回调函数

2,说明

1, useReducer 和 redux中的Reducer是一样的,说白了Reducer就是一个函数
2, useReducer()是一个函数,有三个参数, 第一个参数:reducer, 第二个参数:初始值, 第三个参数:init
3, useReducer()返回值是一个数组,第一个是state, 第二个是dispatch
4, const [state, dispatch] = useReducer(reducer, 初始值)

3, 举例

import './App.css';
import React , { useReducer } from 'react'



function App() {
    const [state, dispatch] = useReducer((state, action)=> {
        switch(action.type) {
            case 'setname':
                 return {...state, name: action.name}
            case 'setage':
                 return {...state, age: action.age}
            default:
                 return state
        }
    }, {name: 'zlm', age: 19})
   
  return (
    <>
      <h2>姓名:{state.name}, age: {state.age}</h2>
      <button onClick={ ()=> {
          dispatch({
              type: 'setname',
              name: 'Jamied'
          })
      }}>setName</button>
      <button onClick={()=> {
          dispatch({
              type: 'setage',
              age: '30'
          })
      }}>setAge</button>
     </>
  );
}

export default App;

注意:

useReducer, useContext, createContext = redux
可以实现redux功能