Hook在Vue3中的使用分享

595 阅读3分钟

目录

  1. 为什么会分享这样一篇文章(拙见)
  2. Hook简介
  3. 在Vue3中利用Hook

为什么会分享这样一篇文章(拙见)

我们先了解一下Vue3最基础的变量赋值, const name = ref(''); name.value = '小明',没有了this,很是方便。当然了还有Reactive、defineProps等。功能是实现了,可是代码中出现了大量的赋值语句,代码语义感不强。Hook思想能够使我的代码更容易阅读,这种集成更方便管理。

Hook简介(使你在无需修改组件结构的情况下复用状态逻辑)

  • 引用React对于Hook的定义:Hook是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。 React定义变量,声明一个新的叫做 “count” 的 state 变量 const [count, setCount] = useState(0);
  • Vue3中的Hook类似于Vue2中的mixin,mixin存在一下缺点:
    • 多个mixin之间无法传递状态
    • 命名冲突
    • 隐含的依赖关系(mixin和使用它的组件之间没有层次关系。组件里的变量名称修改后,mixin里没改) 这也是Composition API产生的原因之一。

在Vue3中自定义Hook函数

Vue3常用的定义响应式变量的ref,响应式对象的reactive。看如下代码: 捕获.PNG

hook封装后的代码:

hooks.PNG

不难发现useState、useReducer、useReactive定义的变量、对象更利于我们管理代码,避免过多的赋值语句。看一下他们内部是如何封装的

useState:

// 返回一个状态与设置状态的函数一一对应
import { ref } from 'vue';
const states = [];
const stateSetters = [];
let stateIndex = 0;

function createState (initialState, stateIndex) {
    const state = ref(initialState); // 变成数据响应式
    return state[stateIndex] !== undefined ? state[stateIndex] : state;
}

// 设置state,参数可以是函数或是变量
function createStateSetter (stateIndex) {
    // setCount(variable or function)
    return function (newState) {
        if (typeof newState === 'function') { 
            states[stateIndex].value = newState(states[stateIndex]);
        } else {
            states[stateIndex].value = newState;
        }
    }
}

function useState (initialState) {
    states[stateIndex] = createState(initialState, stateIndex);
    if (!stateSetters[stateIndex]) {
        stateSetters.push(createStateSetter(stateIndex));
    }
    
    const _state = states[stateIndex];
    const _setState = stateSetters[stateIndex];

    stateIndex ++;

    return [
        _state,
        _setState
    ]
}

export default useState;

useReactive:

import {reactive, toRefs} from 'vue';
function useReactive (initialState) {
    if (Object.prototype.toString.call(initialState) !== '[object Object]') {
        throw new TypeError(`The parameter of useReactive must be an Object`);
    }
    const state = reactive(initialState);
    const stateRefs = toRefs(state);
    const setState = (key, value) => {
        // eslint-disable-next-line no-prototype-builtins
        if (Object.prototype.toString.call(key) !== '[object Object]' && !initialState.hasOwnProperty(key)) {
            throw new ReferenceError(`Can't find the property ${ key } from the Object`);
        }

        if (Object.prototype.toString.call(key) !== '[object Object]') {
            for (let k in key) {
                // eslint-disable-next-line no-prototype-builtins
                if (initialState.hasOwnProperty(k)) {
                    state[k] = key[k];
                }
            }
        } else { // value可能是一个函数
            if (typeof(value) === 'function') {
                state[key] = value(state[key]);
            } else {
                state[key] = value;
            }
        }
    }
    return [
        state,
        setState,
        stateRefs // 使用时不用toRefs,直接拓使用拓展运算符即可
    ]
}

export default useReactive;

useReducer:

import useState from './useState';

function useReducer (reducer, initialState) {
    const [state, setState ] = useState(initialState); // 声明响应式数据
    // {type: ???, payload: ???}
    const dispatch = (action) => {
        if (Object.prototype.toString.call(action) !== '[object Object]') {
            throw new TypeError(`The parameter 'action' must be the type 'Object`);

        }

        // eslint-disable-next-line no-prototype-builtins
        if (!action.hasOwnProperty('type')) {
            throw new ReferenceError(`The parameter 'action' need a property 'type`)
        }

        reducer(state, setState, action);
    }
    return [
        state,
        dispatch
    ]
}
export default useReducer;

在视图中的使用:

yingyong.PNG

总结:

以上内容是一种思想吧,给我这种前端小学生带来了很深刻的思考,从会用到这种二次封装,更好得进步。或许对大家有些许帮助,谢谢阅读,欢迎提出宝贵的批评与建议。