React 其他常用Hooks

1. useImperativeHandle

  • 在react中父组件可以通过forwardRef将ref转发到子组件;
  • 子组件拿到父组件创建的ref,绑定到自己的某个元素;
forwardRef的做法本身没有什么问题,但是我们是将子组件的DOM直接暴露给了父组件,某下情况可能造成不可控的问题, 父组件可以拿到DOM后进行任意的操作
通过 useImperativeHandle:
可以只暴露固定的操作, 通过useImperativeHandle的Hook,将传入的ref和useImperativeHandle第二个参数返回的对象绑定到了一起,在父组件调用子组件的方法时,通过自定义实现,让父组件使用返回的对象;
import React, { memo, useRef, forwardRef, useImperativeHandle } from 'react'

const HelloWorld = memo(forwardRef((props, ref) => {

  const inputRef = useRef()

  // 子组件对父组件传入的ref进行处理
  useImperativeHandle(ref, () => {
    return {
      focus() {
        console.log("focus")
        inputRef.current.focus()
      },
      setValue(value) {
        inputRef.current.value = value
      }
    }
  })

  return <input type="text" ref={inputRef}/>
}))


const App = memo(() => {
  const titleRef = useRef()
  const inputRef = useRef()

  function handleDOM() {
    // console.log(inputRef.current)
    inputRef.current.focus()
    // inputRef.current.value = ""
    inputRef.current.setValue("哈哈哈")
  }

  return (
    <div>
      <h2 ref={titleRef}>哈哈哈</h2>
      <HelloWorld ref={inputRef}/>
      <button onClick={handleDOM}>DOM操作</button>
    </div>
  )
})

export default App

2. useLayoutEffect

useLayoutEffect看起来和useEffect非常的相似,事实上他们也只有一点区别而已:

  • useEffect会在渲染的内容更新到DOM上后执行,不会阻塞DOM的更新;
  • useLayoutEffect会在渲染的内容更新到DOM上之前执行,会阻塞DOM的更新;

如果我们希望在某些操作发生之后再更新DOM,那么应该将这个操作放到useLayoutEffect。

3. redux hooks

redux开发中,为了让组件和redux结合起来,我们使用了react-redux中的connect:
  • 这种方式必须使用高阶函数结合返回的高阶组件;
  • 必须编写:mapStateToProps和 mapDispatchToProps映射的函数;

Redux7.1开始,提供了Hook的方式,我们再也不需要编写connect以及对应的映射函数

useSelector的作用是将state映射到组件中:

  • 参数一:将state映射到需要的数据中;
  • 参数二:可以进行比较来决定是否组件重新渲染(react-redux中提供了shallowEqual进行比较);
useDispatch: 直接获取dispatch函数,之后在组件中直接使用即可;
import React, { memo } from 'react'
import { useSelector, useDispatch, shallowEqual } from "react-redux"
import { addNumberAction, changeMessageAction, subNumberAction } from './store/modules/counter'


// memo高阶组件包裹起来的组件有对应的特点: 只有props发生改变时, 才会重新渲染
const Home = memo((props) => {
  const { message } = useSelector((state) => ({
    message: state.counter.message
  }), shallowEqual) // shallowEqual优化,只有当组件内使用的state.message改变时重新加载  不会由于父组件更新了state的其他参数重新渲染

  const dispatch = useDispatch()
  function changeMessageHandle() {
    dispatch(changeMessageAction("你好啊, 师姐!"))
  }

  console.log("Home render")

  return (
    <div>
      <h2>Home: {message}</h2>
      <button onClick={e => changeMessageHandle()}>修改message</button>
    </div>
  )
})


const App = memo((props) => {
  // 1.使用useSelector将redux中store的数据映射到组件内
  const { count } = useSelector((state) => ({
    count: state.counter.count
  }), shallowEqual)

  // 2.使用dispatch直接派发action
  const dispatch = useDispatch()
  function addNumberHandle(num, isAdd = true) {
    if (isAdd) {
      dispatch(addNumberAction(num))
    } else {
      dispatch(subNumberAction(num))
    }
  }

  console.log("App render")

  return (
    <div>
      <h2>当前计数: {count}</h2>
      <button onClick={e => addNumberHandle(1)}>+1</button>
      <button onClick={e => addNumberHandle(6)}>+6</button>
      <button onClick={e => addNumberHandle(6, false)}>-6</button>

      <Home/>
    </div>
  )
})

export default App

4. useTransition

返回一个状态值表示过渡任务的等待状态,以及一个启动该过渡任务的函数。
打个比方:搜索过滤,在输入框输入时,对于上w条数据时,会存在卡顿,是由于在搜索的输入事件中,event.target.value更新与过滤出来的数据同时更新,导致输入存在卡顿原因。通过useTransition 在告诉react对于某部分任务的更新优先级较低,可以稍后进行更新。
useTransition返回两个参数。
import React, { memo, useState, useTransition } from 'react'
import namesArray from './namesArray'

const App = memo(() => {
  const [showNames, setShowNames] = useState(namesArray)
  const [ pending, startTransition ] = useTransition()

  function valueChangeHandle(event) {
    startTransition(() => {
      const keyword = event.target.value
      const filterShowNames = namesArray.filter(item => item.includes(keyword))
      setShowNames(filterShowNames)
    })
  }

  return (
    <div>
      <input type="text" onInput={valueChangeHandle}/>
      <h2>用户名列表: {pending && <span>data loading</span>} </h2>
      <ul>
        {
          showNames.map((item, index) => {
            return <li key={index}>{item}</li>
          })
        }
      </ul>
    </div>
  )
})

export default App
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值