使用vue-hooks完成类似于React的useState
前言
在使用vue3的过程中,通常使用 ref()完成对应的响应式,但是在使用过程中我们需要使用.value来获取到真正的值,从而实现响应式,在开发过程中经常会忘记.value,本文主要是想解决一下类类似这方面的问题
对比React
使用React过程中,我们发现使用useState Hook给我们带来了很多便利的地方,通过useState,可以返回一个数组,并且从中可以结构出我们需要的响应式数据和对数据的修改方法
const [state,useState] = useState(0)
vue3的联想
现在我们使用的是vue3,我们是否可以写出类似的Hooks来完成对这方面的优化呢?答案是可以的。Vue3中提出了composition API,实现了组合式API,对比与Option API,Composition API
- 其代码更易读,更易理解和学习,没有任何幕后操作
- Composition API的好处不仅仅是以不同的方式进行编码,更重要的是对于代码的重用
- 不受模板和组件范围的限制,也可以准确的知道我们可以使用哪些属性
- 由于幕后没有什么操作,所以编辑器可以帮助我们进行类型检查和建议
所以我们可以试试是否可以写出对应的Hooks在Vue3的基础上,对Ref进行二次封装
准备工作
创建vite项目,我们使用的vue3-ts
在命令行输入
npm create vite@latest // 安装vite
按下回车我们选择 vue3-ts,并且按下回车,进行安装,安装成功之后进入项目目录
npm i //安装依赖
构建项目架构
在src目录中添加一个文件夹Hooks,我们将在里面完成我们对应个Hooks操作
在Hooks文件夹中创建index.ts文件,用于导出我们写好的hooks
/*
* @Author: liming-pan
* @Date: 2022-04-27 13:02:21
* @LastEditors: liming-pan
* @FilePath: \vue-hooks\src\hooks\index.ts
*/
import useState from "./useState";
import useReducer from "./useReducer";
import useReactive from "./useReactive";
export { useReactive, useState, useReducer };
现在我们开始对useState进行构思
参考React中的useState,会返回一个响应式的数以及对响应式数据的操作方法朝着这个目标我们开始写代码
/*
* @Author: liming-pan
* @Date: 2022-04-27 13:04:34
* @LastEditors: liming-pan
* @FilePath: \vue-hooks\src\hooks\useState\index.ts
*/
import { Ref, ref } from "vue";
const states: Ref[] = [];
const stateSetters: Array<any> = [];
let stateIndex: number = 0;
/**
* 主要用于创建一个响应式的数据
* @param initalState 初始state
* @param stateIndex state对应的下标
* @returns 判断已有数组中是否存在,如果不存在,则返回这个数据,如果存在了则就返回原有数据中对应的数据
*/
function createState<T>(initalState: T, stateIndex: number) {
const state = ref<T>(initalState);
return states[stateIndex] !== undefined ? states[stateIndex] : state;
}
/**
* 完成函数的返回
* @param stateIndex 传入state对应的下标
* @returns 根据类型进行判断,如果是方法,则执行后的结构赋值给响应式的数据,如果不是函数类型,那么我们就将传递过来的新的值的进行赋值
*/
function createStateSetters(stateIndex: number) {
return function (newState: any) {
if (typeof newState === "function") {
states[stateIndex].value = newState(states[stateIndex]);
} else {
states[stateIndex].value = newState;
}
};
}
/**
* useState Hooks
* @param initalState 暴露出去的方法,在外界使用时,仅需传入初始值
* @returns 返回一个响应式的数据,以及返回一个可以对数据进行操作的操作函数
*/
function useState<T>(initalState: T) {
states[stateIndex] = createState(initalState, stateIndex);
if (!stateSetters[stateIndex]) {
stateSetters.push(createStateSetters(stateIndex));
}
const _state = states[stateIndex];
const _setState = stateSetters[stateIndex];
stateIndex++;
return [_state, _setState];
}
export default useState;
总结
在这里我们就完成了对应的useStateHooks的完成我们在组件进行测试
<!--
* @Author: liming-pan
* @Date: 2022-04-27 12:57:22
* @LastEditors: liming-pan
* @FilePath: \vue-hooks\src\App.vue
-->
<script setup lang="ts">
import { useState } from "./hooks";
const [count1, setCount1] = useState<number>(0);
</script>
<template>
<div>
<div>
<h1>{{ count1 }}</h1>
<button @click="setCount1((count: any) => count.value + 1)">ADD</button>
<button @click="setCount1(count1 - 1)">JIAN</button>
</div>
</div>
</template>
<style></style>
测试结果为
完成我们想要得到的Hooks效果,在经过Hooks并没有丢失其响应式同时也在某种程度上减少了.value的书写,增加了数据的可读性