目录
- 为什么会分享这样一篇文章(拙见)
- Hook简介
- 在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。看如下代码:
hook封装后的代码:
不难发现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;
在视图中的使用:
总结:
以上内容是一种思想吧,给我这种前端小学生带来了很深刻的思考,从会用到这种二次封装,更好得进步。或许对大家有些许帮助,谢谢阅读,欢迎提出宝贵的批评与建议。