Hooks

贡献 React Hooks 的详细指南

概述

Hooks 是可复用的 React 自定义 Hook,用于封装常用的状态逻辑和副作用。

创建 Hook

1. 生成 Hook 模板

npm run registry:create <hook-name> --type hook

Hook 名称应该以 use- 开头,如 use-local-storageuse-debounce 等。

生成的目录结构:

registry/ssp/hook/<hook-name>/
├── index.ts           # Hook 源代码
├── index.json         # Hook 注册信息
└── README.mdx         # Hook 文档

2. 安装依赖

如果 Hook 需要外部依赖:

npm i <package-name>

更新 index.json

registry/ssp/hook/<hook-name>/index.json
{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "use-hook-name",
  "type": "registry:hook",
  "dependencies": [
    "react"
  ]
}

3. 实现 Hook

编辑 index.ts 文件:

registry/ssp/hook/<hook-name>/index.ts
import { useState, useEffect, useCallback } from "react"

export interface UseHookOptions {
  defaultValue?: string
  onStateChange?: (value: string) => void
}

export interface UseHookReturn {
  value: string
  setValue: (value: string) => void
  reset: () => void
}

/**
 * Custom hook description
 * @param options - Hook configuration options
 * @returns Hook return value
 */
export function useHookName(options: UseHookOptions = {}): UseHookReturn {
  const { defaultValue = "", onStateChange } = options
  const [value, setValue] = useState<string>(defaultValue)

  const handleSetValue = useCallback((newValue: string) => {
    setValue(newValue)
    onStateChange?.(newValue)
  }, [onStateChange])

  const reset = useCallback(() => {
    setValue(defaultValue)
  }, [defaultValue])

  useEffect(() => {
    // Side effects here
  }, [value])

  return {
    value,
    setValue: handleSetValue,
    reset,
  }
}

4. 编写文档

编辑 README.mdx 文件:

registry/ssp/hook/<hook-name>/README.mdx
---
title: useHookName
---

## 安装

<RegistryDownload filename="use-hook-name.json" />

## 用法

```tsx
import { useHookName } from "@/hooks/use-hook-name"

function MyComponent() {
  const { value, setValue, reset } = useHookName({
    defaultValue: "initial",
    onStateChange: (newValue) => {
      console.log("Value changed:", newValue)
    }
  })

  return (
    <div>
      <input 
        value={value} 
        onChange={(e) => setValue(e.target.value)} 
      />
      <button onClick={reset}>Reset</button>
    </div>
  )
}

API

参数

参数类型默认值描述
optionsUseHookOptionsHook 配置选项
options.defaultValuestring""默认值
options.onStateChange(value: string) => void-状态变化回调

返回值

属性类型描述
valuestring当前值
setValue(value: string) => void设置值的函数
reset() => void重置到默认值

示例

基本用法

[基本示例代码]

高级用法

[高级示例代码]


## Hook 类型示例

### 状态管理 Hook

```typescript
// use-local-storage
export function useLocalStorage<T>(
  key: string,
  initialValue: T
): [T, (value: T) => void] {
  // Implementation
}

数据获取 Hook

// use-api
export function useApi<T>(url: string) {
  return {
    data: T | null,
    loading: boolean,
    error: Error | null,
    refetch: () => void
  }
}

工具类 Hook

// use-debounce
export function useDebounce<T>(value: T, delay: number): T {
  // Implementation
}

副作用 Hook

// use-click-outside
export function useClickOutside(
  ref: RefObject<HTMLElement>,
  callback: () => void
): void {
  // Implementation
}

最佳实践

1. 命名规范

  • 总是以 use 开头
  • 使用 kebab-case 格式(文件名)
  • 使用 camelCase 格式(函数名)

2. TypeScript 类型

  • 为所有参数和返回值定义类型
  • 使用泛型支持类型推断
  • 导出相关的 TypeScript 接口

3. 性能优化

  • 使用 useCallback 包装函数
  • 使用 useMemo 缓存计算结果
  • 正确设置依赖数组

4. 错误处理

export function useAsyncOperation() {
  const [error, setError] = useState<Error | null>(null)
  
  const execute = useCallback(async () => {
    try {
      setError(null)
      // Async operation
    } catch (err) {
      setError(err instanceof Error ? err : new Error('Unknown error'))
    }
  }, [])
  
  return { execute, error }
}

5. 文档完整性

  • 提供清晰的 JSDoc 注释
  • 包含使用示例
  • 说明所有参数和返回值
  • 提及性能注意事项

测试

为 Hook 编写测试:

import { renderHook, act } from '@testing-library/react'
import { useHookName } from './use-hook-name'

describe('useHookName', () => {
  it('should initialize with default value', () => {
    const { result } = renderHook(() => useHookName())
    expect(result.current.value).toBe("")
  })

  it('should update value', () => {
    const { result } = renderHook(() => useHookName())
    
    act(() => {
      result.current.setValue("new value")
    })
    
    expect(result.current.value).toBe("new value")
  })
})

下一步

完成 Hook 开发后,查看 文档生成与同步 了解如何发布 Hook。