npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@flow97/react-toolkit

v0.1.13

Published

一套面向企业级应用的前端工具集,基于 React、Ant Design 与 TanStack Query。开箱即用的应用壳、权限/菜单、通用列表(分页/无限滚动)、抽屉/弹框表单与国际化支持,助你快速搭建一致、可维护的中后台应用。

Readme

@flow97/react-toolkit

一套面向企业级应用的前端工具集,基于 React、Ant Design 与 TanStack Query。开箱即用的应用壳、权限/菜单、通用列表(分页/无限滚动)、抽屉/弹框表单与国际化支持,助你快速搭建一致、可维护的中后台应用。

亮点特性

  • 应用壳与导航:Layout、侧边菜单、面包屑、登录页、404
  • 列表范式:QueryList(分页)、InfiniteList(无限滚动)
  • 表单弹层:useFormModaluseFormDrawer
  • 权限体系:RequireAuthAuthButton,以及权限/菜单路由片段
  • 数据获取:服务层 hooks(如 useAuthuseMenuListuseGames
  • 子路径导出按域组织,Tree Shaking 友好

安装与要求

pnpm add @flow97/react-toolkit

对等依赖(需由你的应用提供):

  • react、react-dom:^19
  • antd:^6
  • react-router:^7
  • @tanstack/react-query:^5

样式:

import '@flow97/react-toolkit/style.css'

快速上手

import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import 'react-toolkits/style.css'
import { createRoot } from 'react-dom/client'
import { RouterProvider } from 'react-router'
import { ToolkitProvider } from 'react-toolkits/components'
import { AuthMode } from 'react-toolkits/constants'

import router from './router'

// 创建 QueryClient 实例
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      refetchOnWindowFocus: false,
      retry: false,
      staleTime: 5 * 60 * 1000,
      gcTime: 10 * 60 * 1000,
    },
    mutations: {
      retry: false,
    },
  },
})

const root = createRoot(document.getElementById('root') as HTMLElement)

root.render(
  <QueryClientProvider client={queryClient}>
    <ToolkitProvider collapsible gameApiV2 auth={{ mode: AuthMode.GROUP_BASED }} loginPath="/sign_in" mainPagePath="/">
      <RouterProvider router={router} />
    </ToolkitProvider>
  </QueryClientProvider>,
)

重要提示QueryClientProvider 必须包裹 ToolkitProvider,因为 react-toolkits 内部使用了 @tanstack/react-query 的 hooks(如 useQueryClientuseQueryuseMutation)。

配置项(ToolkitProvider

  • loginPath: 登录页路径(未鉴权时会跳转)
  • mainPagePath: 登录后主页路径(鉴权通过时进入)
  • auth.mode: 认证模式,建议使用 AuthMode.GROUP_BASED
  • collapsible: 侧边栏是否可折叠
  • gameApiV2: 是否启用游戏相关 V2 接口适配(如不涉及可忽略)
  • 其余高级配置见类型定义 react-toolkits/components 内导出的 Provider Props

子路径导出(推荐)

  • react-toolkits/components:组件与 Hooks(如 LayoutToolkitProviderInfiniteList
  • react-toolkits/hooks:表单弹层 Hooks(如 useFormDraweruseFormModal
  • react-toolkits/pages:内置页面与路由片段(如 permissionRoutesmenuRoutesSignIn
  • react-toolkits/services:请求相关 Hooks(如 useAuthuseMenuListuseGames
  • react-toolkits/constants:常量与枚举(如 APP_ID_HEADERAuthMode
  • react-toolkits/types:公共类型
  • react-toolkits/utils:工具函数
  • react-toolkits/localereact-toolkits/locale/*:国际化资源与工具

示例:

import { Layout } from 'react-toolkits/components'
import { useFormDrawer } from 'react-toolkits/hooks'
import { permissionRoutes } from 'react-toolkits/pages'
import { useAuth } from 'react-toolkits/services'
import { APP_ID_HEADER } from 'react-toolkits/constants'
import type { NavMenuItem } from 'react-toolkits/types'

权限与菜单集成示例

import { createBrowserRouter } from 'react-router'
import { Layout } from 'react-toolkits/components'
import { permissionRoutes, menuRoutes, SignIn } from 'react-toolkits/pages'

const router = createBrowserRouter([
  {
    path: '/',
    element: <Layout />, // 自动接入面包屑、侧边栏与鉴权
    children: [
      // 权限/菜单内置片段(可按需选择)
      ...permissionRoutes,
      ...menuRoutes,
    ],
  },
  { path: '/sign_in', element: <SignIn /> },
])

export default router

国际化(Locale)

内置基础语言包与上下文工具,也可与第三方 i18n 方案并存:

import { useTranslation } from 'react-toolkits/locale'
import zhCN from 'react-toolkits/locale/zh_CN'
import enGB from 'react-toolkits/locale/en_GB'

const { t } = useTranslation()
// t('FilterFormWrapper.confirmText') → "查询"

如果你已使用 react-i18next 等,可以仅复用本包的页面/菜单能力。

自定义菜单文案

  • 使用 react-toolkits/localeuseTranslation 配合内置 key,或在你的 i18n 方案中映射同名 key
  • 可按需引入 react-toolkits/locale/zh_CNen_GB 等作为基础词条

目录结构(概览)

src/
  components/        // 组件与 Hooks(以 react-toolkits/components 导出)
  hooks/             // 表单弹层 Hooks(以 react-toolkits/hooks 导出)
  features/          // 特性模块(权限/菜单等:hooks/组件/服务聚合)
  pages/             // 内置页面与路由片段
  services/          // 数据服务 hooks(依赖 libs/ky 与全局上下文)
  constants/         // 常量与枚举
  utils/             // 工具函数
  locale/            // 国际化上下文与语言包

常用用法示例

列表(分页 QueryList

import { QueryList } from 'react-toolkits/components'

export default function UserTable() {
  return (
    <QueryList
      queryKey={['users']}
      queryFn={async ({ page, pageSize }) => {
        // 返回 { list: T[]; total: number }
        const res = await fetch(`/api/users?page=${page}&pageSize=${pageSize}`)
        return res.json()
      }}
      columns={[
        { title: 'ID', dataIndex: 'id' },
        { title: 'Name', dataIndex: 'name' },
      ]}
    />
  )
}

列表(无限滚动 InfiniteList

import { InfiniteList } from 'react-toolkits/components'

export default function LogList() {
  return (
    <InfiniteList
      queryKey={['logs']}
      queryFn={async ({ pageParam = 1 }) => {
        // 返回 { list: T[]; nextPage?: number }
        const res = await fetch(`/api/logs?page=${pageParam}`)
        return res.json()
      }}
      itemRender={item => <div>{item.message}</div>}
    />
  )
}

表单弹层(useFormDrawer

import { Button } from 'antd'
import { useFormDrawer } from 'react-toolkits/hooks'

export default function CreateUser() {
  const { show, drawer } = useFormDrawer({
    title: '新建用户',
    onConfirm: async values => {
      await fetch('/api/users', { method: 'POST', body: JSON.stringify(values) })
    },
    content: (
      <>
        <Form.Item name="name" label="姓名" rules={[{ required: true }]}>
          <Input />
        </Form.Item>
        <Form.Item name="role" label="角色" rules={[{ required: true }]}>
          <Select
            options={[
              { value: 'admin', label: '管理员' },
              { value: 'user', label: '用户' },
            ]}
          />
        </Form.Item>
      </>
    ),
  })

  return (
    <>
      <Button onClick={show}>新建</Button>
      {drawer}
    </>
  )
}

表单弹层(useFormModal

import { Button, Form, Input, Select } from 'antd'
import { useFormModal } from 'react-toolkits/hooks'

export default function EditUser() {
  const { show, modal } = useFormModal({
    title: '编辑用户',
    onConfirm: async values => {
      await fetch('/api/users', { method: 'PUT', body: JSON.stringify(values) })
    },
    content: (
      <>
        <Form.Item name="name" label="姓名" rules={[{ required: true }]}>
          <Input />
        </Form.Item>
        <Form.Item name="role" label="角色" rules={[{ required: true }]}>
          <Select
            options={[
              { value: 'admin', label: '管理员' },
              { value: 'user', label: '用户' },
            ]}
          />
        </Form.Item>
      </>
    ),
  })

  return (
    <>
      <Button onClick={() => show({ initialValues: { name: 'John', role: 'user' } })}>编辑</Button>
      {modal}
    </>
  )
}

服务层 Hooks(react-toolkits/services

import { useAuth, useMenuList } from 'react-toolkits/services'

export function UseDataExample() {
  const { data: permissions } = useAuth()
  const { data: menus } = useMenuList()
  // 根据你的业务渲染
  return null
}

Ky 与请求拦截(useKy

  • 内置 useKy 封装了鉴权与 APP_ID_HEADER 注入逻辑,结合 Provider 的上下文使用
  • 你也可以直接使用 fetch,但推荐统一通过 servicesuseKy
import { useEffect } from 'react'
import { useKy } from 'react-toolkits/components'
import { APP_ID_HEADER } from 'react-toolkits/constants'

export default function FetchWithKy() {
  const ky = useKy({
    headers: {
      [APP_ID_HEADER]: 'my-app-id',
    },
  })

  useEffect(() => {
    ky.get('/api/ping').json()
  }, [ky])

  return null
}

提示:若你的应用已有全局请求层,可仅复用本包页面/组件,将头与鉴权逻辑放到你的层中保持一致性。

迁移指南(从根导入 → 子路径导出)

过去:

import { ToolkitProvider, Layout, useFormDrawer } from '@flow97/react-toolkit'

现在(推荐):

import { ToolkitProvider, Layout } from 'react-toolkits/components'
import { useFormDrawer, useFormModal } from 'react-toolkits/hooks'
import { permissionRoutes } from 'react-toolkits/pages'
import { useAuth } from 'react-toolkits/services'

收益:边界清晰、按需打包更友好(Tree Shaking)。

权限版本兼容

  • 历史上存在不同权限数据结构,AuthMode 用于适配后端变体
  • 新项目建议使用 V3;旧项目如为 V2,只需在 ToolkitProvider 中切换版本

常见问题(FAQ)

  • 如何引入样式?
    • 在应用入口一次性引入:import 'react-toolkits/style.css'
  • Provider 放哪?
    • 在应用根部使用 ToolkitProvider,传入登录路径、主页路径、权限版本等配置。
  • 如何自定义菜单?
    • 通过 Layoutitems 或参考示例应用的 menu-items.tsx
  • 如何统一请求与拦截?
    • 使用 useKyservices 中的 hooks(自动注入鉴权与 App-ID 头)。
    • 若需要自定义拦截,传入 useKy 的配置或在应用层包裹一层。
  • 列表的数据结构需要什么格式?
  • 分页:{ list: T[]; total: number };无限滚动:{ list: T[]; nextPage?: number }
  • 可以只用页面和路由,不用 Provider 吗?
  • 不建议。多数功能依赖上下文(鉴权、国际化、请求)。若必须,请自行在应用层提供等价上下文。

本地开发与构建

# 构建
pnpm -C packages/react-toolkits build

# 开发调试(监听)
pnpm -C packages/react-toolkits dev

构建将产出多入口:lib/index.jslib/components.jslib/hooks.jslib/pages.jslib/services.jslib/types.jslib/utils.js,以及 locale/*

提示:发布前请确保示例应用验证通过,并更新 CHANGELOG.md 描述变更与迁移说明。

变更与发布

  • 更新日志见 CHANGELOG.md
  • 遵循 semver;涉及子路径导出/目录变更会在次版本提供迁移说明

许可证

MIT