React Hooks

54 阅读4分钟

React Hooks 介绍

  • React Hooks是用来做什么的

    1. 对函数型组件进行增强,让函数型组件可以存储状态,可以拥有处理副作用的能力。
    2. 让开发者在不使用类组件的情况下,实现相同的功能。
  • 什么是副作用呢?

    副作用是函数式编程引入的概念,如果一个函数,相同的输入有相同的输出,那么认为该函数是纯函数。这种情况是没有副作用的,但是如果针对该函数引入不确定的代码,导致输出不确定,那么引入的代码就是该函数的副作用。

    在react中,纯函数的概念可以理解为,不管在任何地方渲染,同一个函数,渲染的结果是确认的,所以不是把数据转换成视图的代码,就是副作用代码,比如操作DOM节点,AJAX请求,定时器。

    在类组件中,通常使用生命周期来处理这些副作用,而在函数型组件中,使用HOOKS来处理这些副作用。

useState()

  • 用于为函数组件引入状态

    一个函数当中的变量,在执行完成后,这个变量就会被释放掉,函数型组件本身是不可保存状态数据的,但是在有了useState这个hook以后,函数型组件就可以保留状态,方便下次渲染时使用,useState方法的内部是通过闭包实现保存状态数据的。

  • useState使用上的一些细节

    1. 接收唯一的参数即状态初始值,初始值可以是任意数据类型。
    2. 返回值为数组,数组中存储状态值和更改状态值的方法,方法名称约定以set开头,后面加上状态名称。
    3. 方法可以被调用多次,用来保存不同状态值。
    4. 参数可以是一个函数,函数返回什么,初始状态就是什么,函数只会被调用一次,用在初始值是动态值的情况。(性能优化)
    5. 设置状态值方法本身是异步的。
const [count,setCount] = useState(0);

useReducer()

  • useReducer是另外一种让函数组件保存状态的方式

    与useState的区别是useReducer更方便于集中管理组件状态,可以将改变值的行为都集中在父组件。

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

useContext()

  • 在跨组件层级获取数据时使用。
import {createContext,useContext} from 'react'

const countContext = createContext();

function App() {
 
  return (
    <createContext.Provider value={100}>
      <Foo />
    </createContext.Provider>
  );
}
function Foo() {
  const value = useContext(countContext);
  return <div>{{value}}</div>
}

export default App;

useEffect()

  • 让函数型组件拥有处理副作用的能力,类似生命周期函数。

  • useEffect执行时机。

    1. useEffect(()=>{}),组件挂载,更新时执行
    2. useEffect(()=>{}, []) 组件挂载时执行
    3. useEffect(()=>{ ()=>{} }) 组件卸载前执行
    4. useEffect(()=>{},[count]) 指定数据发生变化时触发useEffect
  • useEffect 使用方法

    1. 为window对象添加滚动事件
    2. 设置定时器让count数值每一秒增加1
  • useEffect 结合异步函数时,不能直接使用async,否则会给hook包裹一层promise

    function App() {
      useEffect(() => {
        (async () => {
          let result = await getData()
        })()
      })
      return (
        <div></div>
      );
    }

useMemo()

  • useMemo的行为类似Vue中的计算属性,可以监测某个值的变化,根据变化值计算新值。
  • useMemo会缓存计算结果,如果检测值没有发生变化,即使组件重新渲染,也不会重新计算,此行为可以有助于避免在每个渲染函数上进行昂贵的计算。
const result = useMemo(() => {
    // 如果count值发生变化时此函数重新执行
    return result;
}, [count])

Memo()

  • 性能优化,如果本组件中的数据没有发生变化,阻止组件更新。
function Foo() {
    return <div></div>
}
export default memoo(Counter)

useCallback()

  • 性能优化,缓存函数,使组件重新渲染时得到相同的函数实例。
    • 如果不加入useCallback,因为传入props的值每次渲染时都会变化,导致Foo组件每次都会重新渲染
import { useState, memo, useCallback } from "react"

function App() {
  const [count, setCount] = useState(0);
  const resetCount = useCallback(() => setCount(0), [setCount])
  return (
    <div>
      <span>{count}</span>
      <button onClick={() => setCount(count + 1)}>+1</button>
      <Foo resetCount={resetCount} />
    </div>
  );
}
const Foo = memo(function Foo(props) {
  console.log("Foo组件重新渲染了");
  return (
    <div>
      我是Foo组件
      <button onClick={props.resetCount}>resetCount</button>
    </div>
  )
})

export default App;

useRef()

  • 获取DOM元素对象。
function App() {
  const username = useRef();
  const handler = () => console.log(username);//{current: input)
  return <input ref={username} onChange={handler} />
}
  • 保存数据,即使组件重新渲染,保存的数据仍然还在,保存的数据被更改不会触发组件重新渲染。
function App() {
  const [count, setCount] = useState(0);
  const timerId = useRef();
  useEffect(() => {
    timerId.current = setInterval(() => {
      setCount(count => count + 1)
    }, 1000);
  });
  const stopCount = function () {
    clearInterval(timerId.current)
  }
  return (
    <div>
      <button onClick={stopCount}>停止定时器{count}</button>
    </div>
  )
}