React Hooks

概念

Class 组件问题:大型组件很难拆分和重构,难于测试,逻辑混乱,复用逻辑复杂如HOC、Render Prop;
函数组件问题:没有组件状态,没有生命周期;
Hooks:有生命周期的函数
规则:调用顺序必须保持一致,即所有钩子函数不能嵌套于 if、for


useState

  • 第一次 render 会初始化 state,re-redner(props 发生变化) 不会重新设置而是替换旧值,只能通过 set 进行修改;
const [count, setCount] = useState<number>(() => 0) // 函数式
  • set 属于异步更新即在函数中多次使用 set 会合并操作, 在react18之前合成事件为异步更新,原生事件是同步更新,在 react18 皆为异步更新
const handleClick = () => {
  setCount(count + 1)
  setCount(count + 1) 
} // + 1
  • 函数无法合并,即每次返回上一次周期的值,可以使用函数形式
const handleFucClick = () => {
  setCount(count => count + 1)
  setCount(count => count + 1)
}
  • 强制更新
const handleSyncClick = () => {
  flushSync(() => {
    setCount(count => count + 1)
  })
  flushSync(() => {
    setCount(count => count + 1)
  })
}

useEffect

  • 没有依赖时( useEffect(() => {}) )可理解为 DidMount + DidUpdate ,组件初始化和 props 更新都会执行
  • 依赖为空值( useEffect(() => {},[]) )相当于 DidMount
  • 存在依赖时,相当于 DidMount + 依赖 DidUpdate
  • 依赖为引用类型会形成死循环,原因是 React 内部使用 Object.is 进行对比,引用地址不一致导致一直进行变化
  • return () => {} 相当于模拟willUnMount但不等于,当 props 发生变化如果没有依赖或者是监听的 props 中的属性,也会执行此函数
useEffect(() => {
  console.log('开始')
  return () => {
    console.log('结束 ')
  }
}, [])

useContext

获取上下文,相比于 Context.Consumer 简单了许多

const StateContext = React.createContext(state)
const UseContextChild: React.FC = () => {
  const value = useContext(StateContext)
  return <div></div>
}

memo

当父组件更新时子组件也会无条件进行重新渲染,使用memo进行包裹缓存组件,相当于 PureCompoennt

const Child: React.FC = memo(() => {}

useMemo

当组件中的某一个值发生改变时,如果存在需要计算的值会重新进行计算,而 useMemo 可以缓存计算结果,只有在依赖项发生变化时才重新计算,类似于 vue 的计算属性

const info = useMemo(() => {
  return {
    // ...
  }
}, [])

useCallback

父组件传入子组件i一个函数,当父组件发生变化,子组件也会重新渲染,将函数缓存配合 memo 使用

const onchange = useCallback(() => {
	// ...
}, [])

useReducer

相当于 useState 加大版,用于处理更庞大且复杂的数据

const initState = { count: 0 }
const reducer = (state = initState, action: any) => {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 }
    case 'decrement':
      return { count: state.count + -1 }
    default:
      return state
  }
}
const [state, dispatch] = useReducer(reducer, initState)

useRef

获取真实 dom 元素

const btnRef = useRef(null)
<div ref={btnRef}>useRef</div>

useTranstion

它用于在处理异步操作时提供平滑的过渡效果,可以帮助你在组件的状态变化时,以动画的方式过渡到新的状态。


自定义 hooks

文件名和函数必须以use开头函数式声明,相当于一个有钩子的函数,返回需要的状态

const useMousePosition = () => {
  const [x, setX] = useState(0)
  const [y, setY] = useState(0)
  useEffect(() => {
    function mouseMoveHandler(event: MouseEvent) {
      setX(event.clientX)
      setY(event.clientY)
    }
    document.body.addEventListener('mousemove', mouseMoveHandler)
    return () => document.body.removeEventListener('mousemove', mouseMoveHandler)
  }, [])
  return [x, y]
}
export default useMousePosition

闭包陷阱

闭包陷阱是指在使用 useState 或 useEffect 这类 Hook 时,由于函数组件的特性,闭包的状态值可能不会按预期更新

const hook = () => {
    let num = 0
    const effect = () => {
        num += 1
        const message = `现在的 num 是 ${num}`
        console.log('message', message)
        return function umount() {
            console.log(message)
        }
    }
    return effect
}
const add = hook()
const umount = add() // 1
add() // 2
add() // 3
add() // 4
add() // 5
umount() // 1 因为作用域问题,取到第一个
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值