react 进阶必学 hook (四):自定义hook

系列文章传送门:

react 进阶必学 hook (一):useState 来一碗大碗宽面

react 进阶必学 hook (二):useEffect 专治不吃宽面

react 进阶必学 hook (三):useContext 面馆分店开张了

react 进阶必学 hook (四):自定义hook

什么是自定义hook

官网原话如下:

自定义 Hook 是一个函数,其名称以 “use” 开头,函数内部可以调用其他的 Hook,自定义 Hook 是一种自然遵循 Hook 设计的约定,而并不是 React 的特性

自定义hook有一下特性或是约定:

在这里插入图片描述

  • 自定义hook中可以调用其他hook
  • 必须以use开头,就像组件必须以大写字母开头一样
  • 自定义hook中管理state也是使用useState、useEffect,因为useState在调用的时候就是完全独立的

自定义hook解决了什么问题

想必开发人员对utils文件夹都很熟悉,在开发的时候我们会把经常使用的一些方法函数放到utils文件夹中,因为这些逻辑方法的复用率很高;同样自定义hook也是解决类似的问题。

React的组件思想其实就是一种将代码复用的做法,然而在编写组件的过程中又有一些逻辑是可以复用的,但是这些逻辑不需要在ui上展示或是有些组件不能在更细的拆分,因此我们可以将这些逻辑抽象成自定义hook,和组件的抽象不是一个纬度,就像抽象工厂模式;这种功能的抽象,严格控制输入输出,还有点函数式编程的思想,自定义的hook我们可以在不同的组件中使用,就像utils中的方法一样。

面馆例子

react 进阶必学 hook (三):useContext 面馆分店开张了中我们添加了一个统计一共卖出多少面的需求,每一个面馆卖出一碗面后都做了两个动作:

  1. 自己面馆的counter显式加一
  2. 面馆总计的counter显式加一

代码如下:

    const [count, setCount] = useState(0); 
    const {counter, add} = useContext(context)

    useEffect(() => {            
        add()
        return window.alert(`一共卖出${counter}碗💪💪💪💪`)
    }, [count])

其中 const [count, setCount] = useState(0);是本面馆的counter,add()控制的是上下文中的总计的counter,两个是分开的,但是仔细想一下,这两个过程其实是严格绑定的,如果添加其他面的品类,添加新的逻辑就会分散导致不好维护,因此可以将这个逻辑写成一个hook。

1. 创建自定义hook

我们先创建一个自定义hook,命名为useCounter,因为要求必须以use开头:

export default function useCounter(initialState) {
    const [count, setCount] = useState(initialState)
    const {counter, add} = useContext(context)
    
    const setCounter = ()=>{
        setCount(count+1)  // 本面馆状态更改
        add()  // 总计更改
    }

    useEffect(() => {
        window.alert(`一共卖出${counter}碗💪💪💪💪`)
    }, [count])

    return [count, setCounter]
}

对于自定义hook的返回return [count, setCounter]中使用[]还是{},要分情况处理,使用时需要更换变量名的话建议用[]

2. 修改面馆逻辑,使用自定义hook

想useState一样使用即可:

const [count, setCount] = useCounter(0);

完整代码如下:

import React, {useState} from 'react';
import useCounter from './useCounter'

export default function Counter(props) {

    const [count, setCount] = useCounter(0);  // 使用自定义hook
    const [big, setSize] = useState(true);
    const [type, setType] = useState("宽面");
    const size = (big)=>big? "大":"小";

    return (
        <div>
            <h3>面馆{props.shop}</h3>
            <h2>老板,来{count}{size(big)}{type}</h2>
            <button onClick={()=> setCount(count+1)} style={{"height":"40px"}}>加一碗</button>
            <button onClick={()=> setSize(!big)} style={{"height":"40px"}}>{size(!big)}</button>
            <button onClick={()=> setType("细面")} style={{"height":"40px"}}>不想吃宽面</button>
        </div>
    );
}

对比一下之前的代码,其实组件内部也干净了不少:

![Peek 2020-05-31 19-29](/home/ffzs/视频/Peek 2020-05-31 19-29.gifexport default function Counter(props) {
    const [count, setCount] = useState(0);
    const [big, setSize] = useState(true);
    const [type, setType] = useState("宽面");
    const size = (big)=>big? "大":"小";

    const {counter, add} = useContext(context)

    useEffect(() => {            
        add()
        return window.alert(`一共卖出${counter}碗💪💪💪💪`)
    }, [count])

    return (
        <div>
            <h3>面馆{props.shop}</h3>
            <h2>老板,来{count}{size(big)}{type}</h2>
            <button onClick={()=> setCount(count+1)} style={{"height":"40px"}}>加一碗</button>
            <button onClick={()=> setSize(!big)} style={{"height":"40px"}}>{size(!big)}</button>
            <button onClick={()=> setType("细面")} style={{"height":"40px"}}>不想吃宽面</button>
        </div>
    );
}

3. 效果展示

在这里插入图片描述

功能跟之前完全相同。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章