Hook必知必会

文章目录

  • 目录
    • Hook解决了什么?
    • Hook的基本使用
    • useState 和 useEffect
    • Hook的使用规则
    • 自定义Hook

目录

Hook解决了什么?

React没有提供将可复用性行为“附加”到组件的途径。(例如,把组件连接到 store)

  1. 问题:组件之间复用状态逻辑很难

在hook出现之前,组件复用一般采用Render Props高阶组件HOC,这类方案需要重新组织你的组件结构,让代码看起来难以理解。React DevTools 中你会发现,由这些抽象层组成的组件会形成“嵌套地狱”。由此可见,React 需要为共享状态逻辑提供更好的原生途径

解决:Hook 使你在无需修改组件结构的情况下复用状态逻辑
2. 问题:组件中各种不相关的逻辑混杂

我们经常会这样,比如组件常常在 componentDidMount 和 componentDidUpdate 中获取数据,同一个 componentDidMount 中可能也包含很多其它的逻辑,如设置事件监听,而之后需在 componentWillUnmount 中清除。相互关联且需要对照修改的代码被进行了拆分,而完全不相关的代码却在同一个方法中组合在一起

解决:Hook 将组件中相互关联的部分拆分成更小的函数

比如:使用useEffect Hook,你可以把组件内相关的副作用组织在一起(例如创建订阅及取消订阅),而不要把它们拆分到不同的生命周期函数里。同时我们又可以使用多个 Effect 实现关注点分离,将不相关的逻辑分离到了多个Effect中。

  1. 无需在使用函数组件还是class组件间苦恼

Hook 使你在非 class 的情况下可以使用更多的 React 特性。

因此,hook是为了解决一类问题出现,它让我们拥抱了函数,更灵活的让组件实现状态逻辑复用。将相关联逻辑行为更集中在更小的函数中处理。

Hook的基本使用

  1. useState() 在函数组件引入状态的钩子
  2. useEffect() 在函数组件中增加操作副作用的操作
const Fruits = () => {
    const [fruits, setFruits] = useState(['苹果', '香蕉'])
    const [fruit, setFruit] = useState(fruits[0])

    useEffect(() => {
       document.title = `你选择了${fruit}`
        
    },[fruit])
    return (
        <>  
            <p>你最爱得水果是{fruit}</p>
            <ul>
                {fruits.map(f => <li key={f} onClick={()=>setFruit(f)}>{f}</li>)}
            </ul>
        </>
    )
}

Hook 的每次调用都有一个完全独立的 state —— 因此你可以在单个组件中多次调用同一个 Hook

useState 和 useEffect

  1. useState
  • count 只在组件首次渲染的时候被创建,通过调用 setCount 来更新当前的 count。组件重新渲染,useState 返回给我们当前最新的 count值。
funciton Clock(){
    const [count, setCount] = useState()
    
    return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

  • setCount()可以传值也可以穿一个函数,一般适用于新的 state 需要通过使用先前的 state 计算得出,参数是旧的state,返回值作为新的state
setCount(preC => preC + 1)
  • useState()可以传一个初始值,也可以传一个返回初始值的函数,该函数只被调用一次。

useState与class组件中的this.state的不同之处

  • useState(initValue),初始值可以是基本数据类型,而不一定是对象。
  • 创建多个状态,需要多次调用useState()
  • state和改变状态的函数需要成对获取,如const [count, setCount] = useState()
  • 更新 state 变量总是替换它而不是合并
  1. useEfect

useEfect 告诉 React 组件需要在渲染后执行某些操作。默认情况下,它在第一次渲染之后和每次更新之后都会执行。即,总是在渲染之后执行,不用去考虑是“挂载”还是“更新”

  1. 通过传入函数的第二个参数来控制useEffect的执行
  • [] 仅在组件挂载和卸载时执行一次
  • [‘count’] 值监听某些值的变化,执行回调
  • 不填 每次渲染后都会被调用
  1. 通过给回调函数返回一个函数来做一些清理工作,比如解绑事件
useEffect(()=>{
    const tim = setTimeout(()=>{
        setCount(count + 1)
    },0)
    
    // 返回一个函数,可选的清除机制
    return function clear(){
        clearTimeout(tim)
    }
},[count])
  1. 按照用途的不同声明多个useEffect,实现关注点分离
  2. React 会在执行当前 effect 之前对上一个 effect 进行清除,有效避免了一些bug
  3. effect的执行时机,与 componentDidMount、componentDidUpdate 不同的是,在浏览器完成布局与绘制之后,传给 useEffect 的函数会延迟调用,如果需要同步调用,则使用useLayoutEffect()

effect 的清除阶段在每次重新渲染时都会执行,而不是只在卸载组件的时候执行一次。

我们可以把 useEffect 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。使用它在函数中执行副作用操作。如:数据获取,设置订阅以及手动更改 React 组件中的 DOM 。

Hook的使用规则

  • 只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。
  • 只能在 React 的函数组件中(或自定义Hook中)调用 Hook。不要在其他 JavaScript 函数中调用。

为什么React知道哪个state对应哪个useState? React 靠的是 Hook 调用的顺序,当我们将hook放入条件,循环,子函数中会让它们执行顺序不可预测,从而导致bug。

自定义Hook

自定义 Hook 是一个函数,其名称以 “use” 开头,函数内部可以调用其他的 Hook

当我们想在两个函数之间共享逻辑时,我们会把它提取到第三个函数中。

比如,实现状态管理

function useReducer(reducer, initialState) {
  const [state, setState] = useState(initialState);

  function dispatch(action) {
    const nextState = reducer(state, action);
    setState(nextState);
  }

  return [state, dispatch];
}

更多关于Hook的正确使用以及最佳实践,可以看React Hooks 详解 + 项目实战

你可能感兴趣的:(React高级,react,hooks)