diff --git a/.dumirc.ts b/.dumirc.ts index f024e3b..dd65151 100644 --- a/.dumirc.ts +++ b/.dumirc.ts @@ -2,6 +2,6 @@ import { defineConfig } from 'dumi'; export default defineConfig({ themeConfig: { - name: '@arvinxu/npm-template', + name: 'zustand-utils', }, }); diff --git a/.fatherrc.ts b/.fatherrc.ts index 5b4b50d..8ee4f1b 100644 --- a/.fatherrc.ts +++ b/.fatherrc.ts @@ -1,6 +1,5 @@ import { defineConfig } from 'father'; export default defineConfig({ - cjs: { output: 'lib' }, esm: { output: 'es' }, }); diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 8160746..1bcc98a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,6 +1,6 @@ --- name: '报告Bug 🐛' -about: 报告 @arvinxu/npm-template 的 bug +about: 报告 zustand-utils 的 bug title: '🐛[BUG]' labels: '🐛 BUG' assignees: '' @@ -35,7 +35,7 @@ assignees: '' ### © 版本信息 -- @arvinxu/npm-template 版本: [e.g. 1.0.0] +- zustand-utils 版本: [e.g. 1.0.0] - 浏览器环境 - 开发环境 [e.g. mac OS] diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 2a7d46d..39479c7 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,6 +1,6 @@ --- name: '功能需求 ✨' -about: 对 @arvinxu/npm-template 的需求或建议 +about: 对 zustand-utils 的需求或建议 title: '👑 [需求]' labels: '👑 Feature' assignees: '' diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index d68d805..1aebe6c 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,6 +1,6 @@ --- name: '疑问或需要帮助 ❓' -about: 对 @arvinxu/npm-template 使用的疑问或需要帮助 +about: 对 zustand-utils 使用的疑问或需要帮助 title: '🧐[问题]' labels: '🧐 Question' assignees: '' diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 735ede7..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,72 +0,0 @@ -# Changelog - -# [1.4.0](https://github.com/arvinxx/npm-template/compare/v1.3.1...v1.4.0) (2023-01-06) - -### ✨ Features - -- 优化默认配置 ([16b8275](https://github.com/arvinxx/npm-template/commit/16b8275)) - -## [1.3.1](https://github.com/arvinxx/npm-template/compare/v1.3.0...v1.3.1) (2023-01-06) - -# [1.3.0](https://github.com/arvinxx/npm-template/compare/v1.2.4...v1.3.0) (2023-01-06) - -### ✨ Features - -- 支持 alpha beta rc 频道的发版 ([0cfe840](https://github.com/arvinxx/npm-template/commit/0cfe840)) - -## [1.2.4](https://github.com/arvinxx/npm-template/compare/v1.2.3...v1.2.4) (2023-01-01) - -### 🐛 Bug Fixes - -- 修正 jest 测试配置问题 ([ed8a6e4](https://github.com/arvinxx/npm-template/commit/ed8a6e4)) - -## [1.2.3](https://github.com/arvinxx/npm-template/compare/v1.2.2...v1.2.3) (2023-01-01) - -### 🐛 Bug Fixes - -- 修正 ISSUE TEMPLATE 中的包名问题 ([e64da9a](https://github.com/arvinxx/npm-template/commit/e64da9a)) - -## [1.2.2](https://github.com/arvinxx/npm-template/compare/v1.2.1...v1.2.2) (2023-01-01) - -### 🐛 Bug Fixes - -- 修正 commitlint 指令 ([f2b380b](https://github.com/arvinxx/npm-template/commit/f2b380b)) - -## [1.2.1](https://github.com/arvinxx/npm-template/compare/v1.2.0...v1.2.1) (2022-12-17) - -### 🐛 Bug Fixes - -- 补充 react 类型依赖 ([c8723ad](https://github.com/arvinxx/npm-template/commit/c8723ad)) - -# [1.2.0](https://github.com/arvinxx/npm-template/compare/v1.1.2...v1.2.0) (2022-12-17) - -### ✨ Features - -- 补充测试与文档 ([15068b4](https://github.com/arvinxx/npm-template/commit/15068b4)) - -## [1.1.2](https://github.com/arvinxx/npm-template/compare/v1.1.1...v1.1.2) (2022-12-17) - -### 🐛 Bug Fixes - -- 修正无法上传到 npm 的问题 ([e2c609d](https://github.com/arvinxx/npm-template/commit/e2c609d)) - -## [1.1.1](https://github.com/arvinxx/module-develop-template/compare/v1.1.0...v1.1.1) (2022-12-17) - -# [1.1.0](https://github.com/arvinxx/module-develop-template/compare/v1.0.0...v1.1.0) (2022-12-17) - -### ✨ Features - -- 使用 Vercel 部署预览 ([f423074](https://github.com/arvinxx/module-develop-template/commit/f423074)) - -# 1.0.0 (2022-12-17) - -### ✨ Features - -- add ci release workflow ([0e7600e](https://github.com/arvinxx/module-develop-template/commit/0e7600e)) -- add release ci ([31f950a](https://github.com/arvinxx/module-develop-template/commit/31f950a)) -- update test config ([c11a3d9](https://github.com/arvinxx/module-develop-template/commit/c11a3d9)) -- 优化 lint 的执行范围 ([c1dc5d3](https://github.com/arvinxx/module-develop-template/commit/c1dc5d3)) - -### 🐛 Bug Fixes - -- fix test ci ([78f4e92](https://github.com/arvinxx/module-develop-template/commit/78f4e92)) diff --git a/README.md b/README.md index eee3135..c118a3e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# @arvinxu/npm-template +# zustand-utils [![NPM version][npm-image]][npm-url] [![NPM downloads][download-image]][download-url] [![install size][npm-size]][npm-size-url] @@ -9,7 +9,7 @@ [gitpod-badge]: https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod -[gitpod-url]: https://gitpod.io/#https://github.com/ant-design/@arvinxu/npm-template +[gitpod-url]: https://gitpod.io/#https://github.com/arvinxx/zustand-utils @@ -18,67 +18,30 @@ -[npm-image]: http://img.shields.io/npm/v/@arvinxu/npm-template.svg?style=flat-square&color=deepgreen&label=latest -[npm-url]: http://npmjs.org/package/@arvinxu/npm-template -[npm-size]: https://img.shields.io/bundlephobia/minzip/@arvinxu/npm-template?color=deepgreen&label=gizpped%20size&style=flat-square -[npm-size-url]: https://packagephobia.com/result?p=@arvinxu/npm-template +[npm-image]: http://img.shields.io/npm/v/zustand-utils.svg?style=flat-square&color=deepgreen&label=latest +[npm-url]: http://npmjs.org/package/zustand-utils +[npm-size]: https://img.shields.io/bundlephobia/minzip/zustand-utils?color=deepgreen&label=gizpped%20size&style=flat-square +[npm-size-url]: https://packagephobia.com/result?p=zustand-utils -[coverage]: https://codecov.io/gh/arvinxx/npm-template/branch/master/graph/badge.svg -[codecov-url]: https://codecov.io/gh/arvinxx/npm-template/branch/master +[coverage]: https://codecov.io/gh/arvinxx/zustand-utils/branch/master/graph/badge.svg +[codecov-url]: https://codecov.io/gh/arvinxx/zustand-utils/branch/master -[test-ci]: https://github.com/arvinxx/npm-template/workflows/Test%20CI/badge.svg -[release-ci]: https://github.com/arvinxx/npm-template/workflows/Release%20CI/badge.svg -[test-ci-url]: https://github.com/arvinxx/npm-template/actions?query=workflow%3ATest%20CI -[release-ci-url]: https://github.com/arvinxx/npm-template/actions?query=workflow%3ARelease%20CI -[download-image]: https://img.shields.io/npm/dm/@arvinxu/npm-template.svg?style=flat-square -[download-url]: https://npmjs.org/package/@arvinxu/npm-template +[test-ci]: https://github.com/arvinxx/zustand-utils/workflows/Test%20CI/badge.svg +[release-ci]: https://github.com/arvinxx/zustand-utils/workflows/Release%20CI/badge.svg +[test-ci-url]: https://github.com/arvinxx/zustand-utils/actions?query=workflow%3ATest%20CI +[release-ci-url]: https://github.com/arvinxx/zustand-utils/actions?query=workflow%3ARelease%20CI +[download-image]: https://img.shields.io/npm/dm/zustand-utils.svg?style=flat-square +[download-url]: https://npmjs.org/package/zustand-utils -## 简介 +## Introduction -这是一个开发 npm 项目的模板,工程框架选型如下: +## createContext -- 构建: father4 -- 文档: dumi2 -- CI: Github Action -- CD: - - 文档发布: 使用 vercel 自动化触发文档站构建; - - npm 发布: 使用 `semantic-release` 实现 npm 包的自动化发布; - -## 快速上手 - -### 安装 - -推荐使用 `pnpm` 安装 - -```bash -pnpm i @arvinxu/npm-template -S -``` - -### 使用 - -基于该仓库模板可以快速创建一个 npm 包的工程化脚手架。 - -## 使用介绍 - -### Step1. 使用该模板创建一个新的仓库 - -点击右上角 `use this template` -> `create a new reposity` 按钮,创建一个新的仓库。 - -### Step2. 初始化项目信息 - -使用编辑器全局替换 `@arvinxu/npm-template` 为你的包名(例如 `antd-style`),执行 `pnpm i` 安装依赖。 - -### Step3. 开始开发 - -## 迭代记录 - -2022.12.17 - 基于蚂蚁研发技术栈配置完成最新的 npm 研发脚手架 - -详情:[CHANGELOG](./CHANGELOG.md) +A replacement createContext from zustand/context that is deprecated in the future. ## License diff --git a/docs/index.md b/docs/index.md index 709037c..d682d10 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,7 @@ --- hero: - title: @arvinxu/npm-template - description: a npm develop template + title: zustand-utils + description: some utils for zustand actions: - text: 快速上手 link: /guide diff --git a/jest.config.ts b/jest.config.ts index 1c70204..2c5fbad 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -17,8 +17,8 @@ const config: Config.InitialOptions = { '!src/.umi-production/**', ], moduleNameMapper: { - '@arvinxu/npm-template/(.*)$': '/src/$1', - '@arvinxu/npm-template': '/src', + 'zustand-utils/(.*)$': '/src/$1', + 'zustand-utils': '/src', '@/(.*)$': '/src/$1', }, // if you require some es-module npm package, please uncomment below line and insert your package name diff --git a/package.json b/package.json index f98770c..0f467f8 100644 --- a/package.json +++ b/package.json @@ -1,27 +1,25 @@ { - "name": "@arvinxu/npm-template", - "version": "1.4.0", - "description": "a npm develop template", + "name": "zustand-utils", + "version": "0.0.0", + "description": "some utils for zustand", "keywords": [ - "npm", - "template" + "zustand" ], - "homepage": "https://github.com/arvinxx/npm-template", + "homepage": "https://github.com/arvinxx/zustand-utils", "bugs": { - "url": "https://github.com/arvinxx/npm-template/issues/new" + "url": "https://github.com/arvinxx/zustand-utils/issues/new" }, "repository": { "type": "git", - "url": "https://github.com/arvinxx/npm-template.git" + "url": "https://github.com/arvinxx/zustand-utils.git" }, "license": "MIT", "author": "arvinxx(arvinx@foxmail.com)", "sideEffects": false, - "main": "lib/index.js", + "main": "es/index.js", "module": "es/index.js", - "types": "lib/index.d.ts", + "types": "es/index.d.ts", "files": [ - "lib", "es" ], "scripts": { @@ -91,7 +89,11 @@ "stylelint": "^14", "ts-jest": "^29", "ts-node": "^10", - "typescript": "^4" + "typescript": "^4", + "zustand": "^4" + }, + "peerDependencies": { + "zustand": ">=4" }, "publishConfig": { "access": "public", diff --git a/tests/index.test.tsx b/tests/index.test.tsx new file mode 100644 index 0000000..a619f43 --- /dev/null +++ b/tests/index.test.tsx @@ -0,0 +1,174 @@ +import { render } from '@testing-library/react'; +import { + Component as ClassComponent, + ReactNode, + StrictMode, + useCallback, + useEffect, + useState, +} from 'react'; +import type { StoreApi } from 'zustand'; +import { create } from 'zustand'; +import { createContext } from 'zustand-utils'; +import { subscribeWithSelector } from 'zustand/middleware'; + +const consoleError = console.error; +afterEach(() => { + console.error = consoleError; +}); + +type CounterState = { + count: number; + inc: () => void; +}; + +it('creates and uses context store', async () => { + const { Provider, useStore } = createContext>(); + + const createStore = () => + create((set) => ({ + count: 0, + inc: () => set((state) => ({ count: state.count + 1 })), + })); + + function Counter() { + const { count, inc } = useStore(); + useEffect(inc, [inc]); + return
count: {count * 1}
; + } + + const { findByText } = render( + <> + + + + , + ); + + await findByText('count: 1'); +}); + +it('uses context store with selectors', async () => { + const { Provider, useStore } = createContext>(); + + const createStore = () => + create((set) => ({ + count: 0, + inc: () => set((state) => ({ count: state.count + 1 })), + })); + + function Counter() { + const count = useStore((state) => state.count); + const inc = useStore((state) => state.inc); + useEffect(inc, [inc]); + return
count: {count * 1}
; + } + + const { findByText } = render( + <> + + + + , + ); + + await findByText('count: 1'); +}); + +it('uses context store api', async () => { + const createStore = () => + create()( + subscribeWithSelector((set) => ({ + count: 0, + inc: () => set((state) => ({ count: state.count + 1 })), + })), + ); + + type CustomStore = ReturnType; + const { Provider, useStoreApi } = createContext(); + + function Counter() { + const storeApi = useStoreApi(); + const [count, setCount] = useState(0); + useEffect( + () => + storeApi.subscribe( + (state) => state.count, + () => setCount(storeApi.getState().count), + ), + [storeApi], + ); + useEffect(() => { + storeApi.setState({ count: storeApi.getState().count + 1 }); + }, [storeApi]); + useEffect(() => { + if (count === 1) { + storeApi.destroy(); + storeApi.setState({ count: storeApi.getState().count + 1 }); + } + }, [storeApi, count]); + return
count: {count * 1}
; + } + + const { findByText } = render( + <> + + + + , + ); + + await findByText('count: 1'); +}); + +it('throws error when not using provider', async () => { + console.error = jest.fn(); + + class ErrorBoundary extends ClassComponent< + { children?: ReactNode | undefined }, + { hasError: boolean } + > { + constructor(props: { children?: ReactNode | undefined }) { + super(props); + this.state = { hasError: false }; + } + static getDerivedStateFromError() { + return { hasError: true }; + } + render() { + return this.state.hasError ?
errored
: this.props.children; + } + } + + const { useStore } = createContext>(); + function Component() { + useStore(); + return
no error
; + } + + const { findByText } = render( + + + + + , + ); + await findByText('errored'); +}); + +const expectAreTypesEqual = () => ({ + toBe: ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _: (() => T extends B ? 1 : 0) extends () => T extends A ? 1 : 0 ? true : false, + ) => {}, +}); + +it('useCallback with useStore infers types correctly', async () => { + const { useStore } = createContext>(); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + function _Counter() { + const _x = useStore(useCallback((state) => state.count, [])); + + expectAreTypesEqual().toBe(true); + } +}); diff --git a/tsconfig.json b/tsconfig.json index c789342..bff8022 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,8 +10,8 @@ "paths": { "@@/*": [".dumi/tmp/*"], "@/*": ["src"], - "@arvinxu/npm-template": ["src"], - "@arvinxu/npm-template/*": ["src/*", "*"] + "zustand-utils": ["src"], + "zustand-utils/*": ["src/*", "*"] } } }