From ed39e50bdf22c314519d692656f54dee086c9a58 Mon Sep 17 00:00:00 2001 From: kalu5 <451660550@qq.com> Date: Fri, 12 Apr 2024 23:18:00 +0800 Subject: [PATCH] feat: useReducer --- .vscode/settings.json | 3 +++ __test__/useReducer.ts | 28 ++++++++++++++++++++++++++++ libs/hooks/index.ts | 2 ++ libs/hooks/useReducer.ts | 22 ++++++++++++++++++++++ libs/types/index.ts | 11 +++++++++++ package.json | 2 +- vitest.config.ts | 1 + 7 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 .vscode/settings.json create mode 100644 __test__/useReducer.ts create mode 100644 libs/hooks/useReducer.ts diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d7207a4 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "node_modules\\typescript\\lib" +} \ No newline at end of file diff --git a/__test__/useReducer.ts b/__test__/useReducer.ts new file mode 100644 index 0000000..234f457 --- /dev/null +++ b/__test__/useReducer.ts @@ -0,0 +1,28 @@ +import { expect, test } from 'vitest' +import type { Ref } from 'vue' +import type { ReturnDisptch } from '../libs/types' + +import { useReducer } from '../libs/main' + +function reducer(state, action) { + if (action.type === 'add') + return state.value + 1 + + return state.value - 1 +} +test('useReducer', () => { + const [state, dispatch] = useReducer(reducer, 1) + expect((state as Ref).value).toBe(1); + (dispatch as ReturnDisptch) ({ type: 'add' }) + expect((state as Ref).value).toBe(2) +}) + +test('useReducer has init ', () => { + const init = (arg: number) => { + return arg + 1 + } + const [state, dispatch] = useReducer(reducer, 1, init) + expect((state as Ref).value).toBe(2); + (dispatch as ReturnDisptch) ({ type: 'add' }) + expect((state as Ref).value).toBe(3) +}) diff --git a/libs/hooks/index.ts b/libs/hooks/index.ts index cfc09e9..b4d94ca 100644 --- a/libs/hooks/index.ts +++ b/libs/hooks/index.ts @@ -1,5 +1,7 @@ import useState from './useState' +import useReducer from './useReducer' export { useState, + useReducer, } diff --git a/libs/hooks/useReducer.ts b/libs/hooks/useReducer.ts new file mode 100644 index 0000000..17478af --- /dev/null +++ b/libs/hooks/useReducer.ts @@ -0,0 +1,22 @@ +import type { Ref } from 'vue' +import type { Action, Init, Reducer, ReturnDisptch, SetStateSetter } from '../types/index' +import { isFunc } from '../utils/index' +import useState from './useState' + +export default function useReducer(reducer: Reducer, initArg: U, init?: Init) { + let lastInit: U = initArg + if (init && isFunc(init)) + lastInit = init(lastInit) + + const [_state, setState] = useState(lastInit) + + const _dispatch = createDispatch(reducer, _state, setState) + + return [_state, _dispatch] +} + +function createDispatch(reducer: Reducer, _state: Ref, setState: SetStateSetter): ReturnDisptch { + return function (action: Action) { + setState (reducer (_state, action)) + } +} diff --git a/libs/types/index.ts b/libs/types/index.ts index 04a5e2f..280d7d8 100644 --- a/libs/types/index.ts +++ b/libs/types/index.ts @@ -1 +1,12 @@ +import type { Ref } from 'vue' + export type SetStateSetter = (newState: U) => void +export interface Action { + type: string +} + +export type Reducer = (state: Ref, action: Action) => T + +export type Init = (init: T) => T + +export type ReturnDisptch = (action: Action) => void diff --git a/package.json b/package.json index 683a283..4d4d954 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@kalu5/vue_hooks", "type": "module", - "version": "1.0.5", + "version": "1.0.6", "private": false, "description": "This is vue3 hooks utils", "author": "lujialong", diff --git a/vitest.config.ts b/vitest.config.ts index d5e043c..5121390 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -2,6 +2,7 @@ import { defineConfig } from 'vitest/config' export default defineConfig({ test: { + include: ['__test__/**'], coverage: { include: [ 'libs/**',