mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-06-11 02:33:10 +08:00
fix: refresh stale technical content in agents, rules, and skills (#2168)
Several published examples contained APIs that no longer exist, code that does not run, or model versions that drifted from reality: - agents/performance-optimizer.md used the web-vitals v3 API (getCLS/getFID/getLCP/getFCP/getTTFB) and reported FID. web-vitals v4 renamed the imports to onCLS/onINP/onLCP/onFCP/onTTFB and FID was replaced by INP (target < 200ms) - rules/common/performance.md pinned stale model versions in the model-selection guidance; refresh to the versions the repo itself uses (agent.yaml pins claude-opus-4-6) and add the PowerShell variant for MAX_THINKING_TOKENS next to the bash export - skills/python-patterns/SKILL.md: both get_value examples referenced default_value without declaring the parameter (NameError); add default_value: Any = None to the EAFP and LBYL signatures - skills/frontend-patterns/SKILL.md: the custom useQuery example rebuilt refetch whenever callers passed inline fetchers/options, re-triggering the effect after every state update (infinite fetch loop). Keep the latest fetcher/options in refs so refetch stays referentially stable. The PASS-labelled useMemo example mutated its input with in-place sort; copy before sorting - skills/coding-standards/SKILL.md repeated the same PASS-labelled in-place-sort-in-useMemo example; same fix - rules/typescript/security.md used a vendor-specific OPENAI_API_KEY in generic guidance; switch to a neutral API_KEY Every hand-maintained copy of the affected content is synced in the same change: locale mirrors (ja-JP, ko-KR, pt-BR, tr, zh-CN, zh-TW - each only where it carries the affected file) and the .agents/.kiro/.cursor harness mirrors. Two structural divergences are left alone and noted here: .kiro/steering/performance.md has no extended-thinking control list to carry the PowerShell variant, and docs/zh-TW/rules/performance.md keeps an older condensed thinking section without the budget-cap line. rules/zh/performance.md is intentionally untouched - the rules/zh tree is being retired in a separate change
This commit is contained in:
committed by
GitHub
parent
36bec90d45
commit
8b24f63ede
@@ -362,14 +362,14 @@ npx lighthouse https://your-app.com --only-categories=performance
|
||||
### Web Vitalsモニタリング
|
||||
|
||||
```typescript
|
||||
// Core Web Vitalsの追跡
|
||||
import { getCLS, getFID, getLCP, getFCP, getTTFB } from 'web-vitals';
|
||||
// Track Core Web Vitals (web-vitals v4 API)
|
||||
import { onCLS, onINP, onLCP, onFCP, onTTFB } from 'web-vitals';
|
||||
|
||||
getCLS(console.log); // Cumulative Layout Shift
|
||||
getFID(console.log); // First Input Delay
|
||||
getLCP(console.log); // Largest Contentful Paint
|
||||
getFCP(console.log); // First Contentful Paint
|
||||
getTTFB(console.log); // Time to First Byte
|
||||
onCLS(console.log); // Cumulative Layout Shift
|
||||
onINP(console.log); // Interaction to Next Paint
|
||||
onLCP(console.log); // Largest Contentful Paint
|
||||
onFCP(console.log); // First Contentful Paint
|
||||
onTTFB(console.log); // Time to First Byte
|
||||
```
|
||||
|
||||
## パフォーマンスレポートテンプレート
|
||||
@@ -393,7 +393,7 @@ getTTFB(console.log); // Time to First Byte
|
||||
| メトリクス | 現在 | 目標 | ステータス |
|
||||
|-----------|------|------|----------|
|
||||
| LCP | X.X秒 | < 2.5秒 | PASS: |
|
||||
| FID | XXms | < 100ms | PASS: |
|
||||
| INP | XXms | < 200ms | PASS: |
|
||||
| CLS | X.XX | < 0.1 | WARNING: |
|
||||
|
||||
## 重大な問題
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
- ペアプログラミングとコード生成
|
||||
- マルチ agent システムのワーカー agent
|
||||
|
||||
**Sonnet 4.5**(最高のコーディングモデル):
|
||||
**Sonnet 4.6**(最高のコーディングモデル):
|
||||
- メイン開発作業
|
||||
- マルチ agent ワークフローのオーケストレーション
|
||||
- 複雑なコーディングタスク
|
||||
|
||||
**Opus 4.5**(最も深い推論):
|
||||
**Opus 4.6**(最も深い推論):
|
||||
- 複雑なアーキテクチャの意思決定
|
||||
- 最大限の推論要件
|
||||
- 調査と分析タスク
|
||||
@@ -37,7 +37,7 @@
|
||||
拡張思考の制御:
|
||||
- **トグル**: Option+T(macOS)/ Alt+T(Windows/Linux)
|
||||
- **設定**: `~/.claude/settings.json` で `alwaysThinkingEnabled` を設定
|
||||
- **予算上限**: `export MAX_THINKING_TOKENS=10000`
|
||||
- **予算上限**: `export MAX_THINKING_TOKENS=10000`(bash)または `$env:MAX_THINKING_TOKENS = "10000"`(PowerShell)
|
||||
- **詳細モード**: Ctrl+O で思考出力を表示
|
||||
|
||||
深い推論を必要とする複雑なタスクの場合:
|
||||
|
||||
@@ -16,10 +16,10 @@ paths:
|
||||
const apiKey = "sk-proj-xxxxx"
|
||||
|
||||
// 常に: 環境変数
|
||||
const apiKey = process.env.OPENAI_API_KEY
|
||||
const apiKey = process.env.API_KEY
|
||||
|
||||
if (!apiKey) {
|
||||
throw new Error('OPENAI_API_KEY not configured')
|
||||
throw new Error('API_KEY not configured')
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -158,28 +158,41 @@ export function useQuery<T>(
|
||||
const [error, setError] = useState<Error | null>(null)
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
// Keep the latest fetcher/options in refs so refetch stays referentially
|
||||
// stable even when callers pass inline functions and object literals.
|
||||
// Without this, every render creates a new refetch, and the effect below
|
||||
// re-runs after each state update - an infinite fetch loop.
|
||||
const fetcherRef = useRef(fetcher)
|
||||
const optionsRef = useRef(options)
|
||||
useEffect(() => {
|
||||
fetcherRef.current = fetcher
|
||||
optionsRef.current = options
|
||||
})
|
||||
|
||||
const refetch = useCallback(async () => {
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
|
||||
try {
|
||||
const result = await fetcher()
|
||||
const result = await fetcherRef.current()
|
||||
setData(result)
|
||||
options?.onSuccess?.(result)
|
||||
optionsRef.current?.onSuccess?.(result)
|
||||
} catch (err) {
|
||||
const error = err as Error
|
||||
setError(error)
|
||||
options?.onError?.(error)
|
||||
optionsRef.current?.onError?.(error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}, [fetcher, options])
|
||||
}, [])
|
||||
|
||||
const enabled = options?.enabled !== false
|
||||
|
||||
useEffect(() => {
|
||||
if (options?.enabled !== false) {
|
||||
if (enabled) {
|
||||
refetch()
|
||||
}
|
||||
}, [key, refetch, options?.enabled])
|
||||
}, [key, enabled, refetch])
|
||||
|
||||
return { data, error, loading, refetch }
|
||||
}
|
||||
@@ -284,8 +297,9 @@ export function useMarkets() {
|
||||
|
||||
```typescript
|
||||
// PASS: useMemo for expensive computations
|
||||
// Copy before sorting - Array.prototype.sort mutates in place
|
||||
const sortedMarkets = useMemo(() => {
|
||||
return markets.sort((a, b) => b.volume - a.volume)
|
||||
return [...markets].sort((a, b) => b.volume - a.volume)
|
||||
}, [markets])
|
||||
|
||||
// PASS: useCallback for functions passed to children
|
||||
|
||||
@@ -56,14 +56,14 @@ Pythonは条件チェックよりも例外処理を好みます。
|
||||
|
||||
```python
|
||||
# Good: EAFP style
|
||||
def get_value(dictionary: dict, key: str) -> Any:
|
||||
def get_value(dictionary: dict, key: str, default_value: Any = None) -> Any:
|
||||
try:
|
||||
return dictionary[key]
|
||||
except KeyError:
|
||||
return default_value
|
||||
|
||||
# Bad: LBYL (Look Before You Leap) style
|
||||
def get_value(dictionary: dict, key: str) -> Any:
|
||||
def get_value(dictionary: dict, key: str, default_value: Any = None) -> Any:
|
||||
if key in dictionary:
|
||||
return dictionary[key]
|
||||
else:
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
- 멀티 에이전트 워크플로우 오케스트레이션
|
||||
- 복잡한 코딩 작업
|
||||
|
||||
**Opus 4.5** (가장 깊은 추론):
|
||||
**Opus 4.6** (가장 깊은 추론):
|
||||
- 복잡한 아키텍처 의사결정
|
||||
- 최대 추론 요구사항
|
||||
- 리서치 및 분석 작업
|
||||
@@ -37,7 +37,7 @@
|
||||
확장 사고 제어 방법:
|
||||
- **전환**: Option+T (macOS) / Alt+T (Windows/Linux)
|
||||
- **설정**: `~/.claude/settings.json`에서 `alwaysThinkingEnabled` 설정
|
||||
- **예산 제한**: `export MAX_THINKING_TOKENS=10000`
|
||||
- **예산 제한**: `export MAX_THINKING_TOKENS=10000` (bash) 또는 `$env:MAX_THINKING_TOKENS = "10000"` (PowerShell)
|
||||
- **상세 모드**: Ctrl+O로 사고 출력 확인
|
||||
|
||||
깊은 추론이 필요한 복잡한 작업:
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
- Orquestrando fluxos de trabalho multi-agente
|
||||
- Tarefas de codificação complexas
|
||||
|
||||
**Opus 4.5** (Raciocínio mais profundo):
|
||||
**Opus 4.6** (Raciocínio mais profundo):
|
||||
- Decisões arquiteturais complexas
|
||||
- Requisitos máximos de raciocínio
|
||||
- Pesquisa e análise
|
||||
@@ -37,7 +37,7 @@ O pensamento estendido está habilitado por padrão, reservando até 31.999 toke
|
||||
Controle o pensamento estendido via:
|
||||
- **Toggle**: Option+T (macOS) / Alt+T (Windows/Linux)
|
||||
- **Config**: Defina `alwaysThinkingEnabled` em `~/.claude/settings.json`
|
||||
- **Limite de orçamento**: `export MAX_THINKING_TOKENS=10000`
|
||||
- **Limite de orçamento**: `export MAX_THINKING_TOKENS=10000` (bash) ou `$env:MAX_THINKING_TOKENS = "10000"` (PowerShell)
|
||||
- **Modo verbose**: Ctrl+O para ver a saída de pensamento
|
||||
|
||||
Para tarefas complexas que requerem raciocínio profundo:
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
- Multi-agent iş akışlarını orkestrasyon
|
||||
- Karmaşık kodlama görevleri
|
||||
|
||||
**Opus 4.5** (En derin akıl yürütme):
|
||||
**Opus 4.6** (En derin akıl yürütme):
|
||||
- Karmaşık mimari kararlar
|
||||
- Maksimum akıl yürütme gereksinimleri
|
||||
- Araştırma ve analiz görevleri
|
||||
@@ -37,7 +37,7 @@ Extended thinking varsayılan olarak etkindir ve dahili akıl yürütme için 31
|
||||
Extended thinking kontrolü:
|
||||
- **Toggle**: Option+T (macOS) / Alt+T (Windows/Linux)
|
||||
- **Config**: `~/.claude/settings.json` içinde `alwaysThinkingEnabled` ayarla
|
||||
- **Budget cap**: `export MAX_THINKING_TOKENS=10000`
|
||||
- **Budget cap**: `export MAX_THINKING_TOKENS=10000` (bash) veya `$env:MAX_THINKING_TOKENS = "10000"` (PowerShell)
|
||||
- **Verbose mode**: Thinking çıktısını görmek için Ctrl+O
|
||||
|
||||
Derin akıl yürütme gerektiren karmaşık görevler için:
|
||||
|
||||
@@ -16,10 +16,10 @@ paths:
|
||||
const apiKey = "sk-proj-xxxxx"
|
||||
|
||||
// DAIMA: Environment variable'lar
|
||||
const apiKey = process.env.OPENAI_API_KEY
|
||||
const apiKey = process.env.API_KEY
|
||||
|
||||
if (!apiKey) {
|
||||
throw new Error('OPENAI_API_KEY not configured')
|
||||
throw new Error('API_KEY not configured')
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -169,28 +169,42 @@ export function useQuery<T>(
|
||||
const [error, setError] = useState<Error | null>(null)
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
// Çağıranlar satır içi fonksiyonlar ve nesne literalleri geçirse bile
|
||||
// refetch'in referans olarak kararlı kalması için en güncel fetcher/options
|
||||
// değerlerini ref'lerde tutun. Bu olmadan her render yeni bir refetch
|
||||
// oluşturur ve aşağıdaki effect her state güncellemesinden sonra yeniden
|
||||
// çalışır - sonsuz bir fetch döngüsü.
|
||||
const fetcherRef = useRef(fetcher)
|
||||
const optionsRef = useRef(options)
|
||||
useEffect(() => {
|
||||
fetcherRef.current = fetcher
|
||||
optionsRef.current = options
|
||||
})
|
||||
|
||||
const refetch = useCallback(async () => {
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
|
||||
try {
|
||||
const result = await fetcher()
|
||||
const result = await fetcherRef.current()
|
||||
setData(result)
|
||||
options?.onSuccess?.(result)
|
||||
optionsRef.current?.onSuccess?.(result)
|
||||
} catch (err) {
|
||||
const error = err as Error
|
||||
setError(error)
|
||||
options?.onError?.(error)
|
||||
optionsRef.current?.onError?.(error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}, [fetcher, options])
|
||||
}, [])
|
||||
|
||||
const enabled = options?.enabled !== false
|
||||
|
||||
useEffect(() => {
|
||||
if (options?.enabled !== false) {
|
||||
if (enabled) {
|
||||
refetch()
|
||||
}
|
||||
}, [key, refetch, options?.enabled])
|
||||
}, [key, enabled, refetch])
|
||||
|
||||
return { data, error, loading, refetch }
|
||||
}
|
||||
@@ -295,8 +309,9 @@ export function useMarkets() {
|
||||
|
||||
```typescript
|
||||
// PASS: Pahalı hesaplamalar için useMemo
|
||||
// Sıralamadan önce kopyalayın - Array.prototype.sort yerinde değiştirir
|
||||
const sortedMarkets = useMemo(() => {
|
||||
return markets.sort((a, b) => b.volume - a.volume)
|
||||
return [...markets].sort((a, b) => b.volume - a.volume)
|
||||
}, [markets])
|
||||
|
||||
// PASS: Alt bileşenlere geçirilen fonksiyonlar için useCallback
|
||||
|
||||
@@ -57,14 +57,14 @@ Python, koşulları kontrol etmek yerine exception handling'i tercih eder.
|
||||
|
||||
```python
|
||||
# İyi: EAFP stili
|
||||
def get_value(dictionary: dict, key: str) -> Any:
|
||||
def get_value(dictionary: dict, key: str, default_value: Any = None) -> Any:
|
||||
try:
|
||||
return dictionary[key]
|
||||
except KeyError:
|
||||
return default_value
|
||||
|
||||
# Kötü: LBYL (Atlamadan Önce Bak) stili
|
||||
def get_value(dictionary: dict, key: str) -> Any:
|
||||
def get_value(dictionary: dict, key: str, default_value: Any = None) -> Any:
|
||||
if key in dictionary:
|
||||
return dictionary[key]
|
||||
else:
|
||||
|
||||
@@ -353,14 +353,14 @@ npx lighthouse https://your-app.com --only-categories=performance
|
||||
### Web Vitals 监控
|
||||
|
||||
```typescript
|
||||
// Track Core Web Vitals
|
||||
import { getCLS, getFID, getLCP, getFCP, getTTFB } from 'web-vitals';
|
||||
// Track Core Web Vitals (web-vitals v4 API)
|
||||
import { onCLS, onINP, onLCP, onFCP, onTTFB } from 'web-vitals';
|
||||
|
||||
getCLS(console.log); // Cumulative Layout Shift
|
||||
getFID(console.log); // First Input Delay
|
||||
getLCP(console.log); // Largest Contentful Paint
|
||||
getFCP(console.log); // First Contentful Paint
|
||||
getTTFB(console.log); // Time to First Byte
|
||||
onCLS(console.log); // Cumulative Layout Shift
|
||||
onINP(console.log); // Interaction to Next Paint
|
||||
onLCP(console.log); // Largest Contentful Paint
|
||||
onFCP(console.log); // First Contentful Paint
|
||||
onTTFB(console.log); // Time to First Byte
|
||||
```
|
||||
|
||||
## 性能报告模板
|
||||
@@ -384,7 +384,7 @@ getTTFB(console.log); // Time to First Byte
|
||||
| 指标 | 当前值 | 目标值 | 状态 |
|
||||
|--------|---------|--------|--------|
|
||||
| LCP | X.X秒 | < 2.5秒 | 通过: |
|
||||
| FID | XX毫秒 | < 100毫秒 | 通过: |
|
||||
| INP | XX毫秒 | < 200毫秒 | 通过: |
|
||||
| CLS | X.XX | < 0.1 | 警告: |
|
||||
|
||||
## 关键问题
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* 编排多智能体工作流
|
||||
* 复杂的编码任务
|
||||
|
||||
**Opus 4.5** (最深的推理能力):
|
||||
**Opus 4.6** (最深的推理能力):
|
||||
|
||||
* 复杂的架构决策
|
||||
* 最高级别的推理需求
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
* **切换**:Option+T (macOS) / Alt+T (Windows/Linux)
|
||||
* **配置**:在 `~/.claude/settings.json` 中设置 `alwaysThinkingEnabled`
|
||||
* **预算上限**:`export MAX_THINKING_TOKENS=10000`
|
||||
* **预算上限**:`export MAX_THINKING_TOKENS=10000`(bash)或 `$env:MAX_THINKING_TOKENS = "10000"`(PowerShell)
|
||||
* **详细模式**:Ctrl+O 查看思考输出
|
||||
|
||||
对于需要深度推理的复杂任务:
|
||||
|
||||
@@ -17,10 +17,10 @@ paths:
|
||||
const apiKey = "sk-proj-xxxxx"
|
||||
|
||||
// ALWAYS: Environment variables
|
||||
const apiKey = process.env.OPENAI_API_KEY
|
||||
const apiKey = process.env.API_KEY
|
||||
|
||||
if (!apiKey) {
|
||||
throw new Error('OPENAI_API_KEY not configured')
|
||||
throw new Error('API_KEY not configured')
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -400,8 +400,9 @@ export async function searchMarkets(
|
||||
import { useMemo, useCallback } from 'react'
|
||||
|
||||
// PASS: GOOD: Memoize expensive computations
|
||||
// Copy before sorting - Array.prototype.sort mutates in place
|
||||
const sortedMarkets = useMemo(() => {
|
||||
return markets.sort((a, b) => b.volume - a.volume)
|
||||
return [...markets].sort((a, b) => b.volume - a.volume)
|
||||
}, [markets])
|
||||
|
||||
// PASS: GOOD: Memoize callbacks
|
||||
|
||||
@@ -169,28 +169,41 @@ export function useQuery<T>(
|
||||
const [error, setError] = useState<Error | null>(null)
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
// Keep the latest fetcher/options in refs so refetch stays referentially
|
||||
// stable even when callers pass inline functions and object literals.
|
||||
// Without this, every render creates a new refetch, and the effect below
|
||||
// re-runs after each state update - an infinite fetch loop.
|
||||
const fetcherRef = useRef(fetcher)
|
||||
const optionsRef = useRef(options)
|
||||
useEffect(() => {
|
||||
fetcherRef.current = fetcher
|
||||
optionsRef.current = options
|
||||
})
|
||||
|
||||
const refetch = useCallback(async () => {
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
|
||||
try {
|
||||
const result = await fetcher()
|
||||
const result = await fetcherRef.current()
|
||||
setData(result)
|
||||
options?.onSuccess?.(result)
|
||||
optionsRef.current?.onSuccess?.(result)
|
||||
} catch (err) {
|
||||
const error = err as Error
|
||||
setError(error)
|
||||
options?.onError?.(error)
|
||||
optionsRef.current?.onError?.(error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}, [fetcher, options])
|
||||
}, [])
|
||||
|
||||
const enabled = options?.enabled !== false
|
||||
|
||||
useEffect(() => {
|
||||
if (options?.enabled !== false) {
|
||||
if (enabled) {
|
||||
refetch()
|
||||
}
|
||||
}, [key, refetch, options?.enabled])
|
||||
}, [key, enabled, refetch])
|
||||
|
||||
return { data, error, loading, refetch }
|
||||
}
|
||||
@@ -295,8 +308,9 @@ export function useMarkets() {
|
||||
|
||||
```typescript
|
||||
// PASS: useMemo for expensive computations
|
||||
// Copy before sorting - Array.prototype.sort mutates in place
|
||||
const sortedMarkets = useMemo(() => {
|
||||
return markets.sort((a, b) => b.volume - a.volume)
|
||||
return [...markets].sort((a, b) => b.volume - a.volume)
|
||||
}, [markets])
|
||||
|
||||
// PASS: useCallback for functions passed to children
|
||||
|
||||
@@ -57,14 +57,14 @@ Python 倾向于使用异常处理而非检查条件。
|
||||
|
||||
```python
|
||||
# Good: EAFP style
|
||||
def get_value(dictionary: dict, key: str) -> Any:
|
||||
def get_value(dictionary: dict, key: str, default_value: Any = None) -> Any:
|
||||
try:
|
||||
return dictionary[key]
|
||||
except KeyError:
|
||||
return default_value
|
||||
|
||||
# Bad: LBYL (Look Before You Leap) style
|
||||
def get_value(dictionary: dict, key: str) -> Any:
|
||||
def get_value(dictionary: dict, key: str, default_value: Any = None) -> Any:
|
||||
if key in dictionary:
|
||||
return dictionary[key]
|
||||
else:
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
- 配對程式設計和程式碼產生
|
||||
- 多 agent 系統中的 worker agents
|
||||
|
||||
**Sonnet 4.5**(最佳程式碼模型):
|
||||
**Sonnet 4.6**(最佳程式碼模型):
|
||||
- 主要開發工作
|
||||
- 協調多 agent 工作流程
|
||||
- 複雜程式碼任務
|
||||
|
||||
**Opus 4.5**(最深度推理):
|
||||
**Opus 4.6**(最深度推理):
|
||||
- 複雜架構決策
|
||||
- 最大推理需求
|
||||
- 研究和分析任務
|
||||
|
||||
@@ -158,28 +158,41 @@ export function useQuery<T>(
|
||||
const [error, setError] = useState<Error | null>(null)
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
// 將最新的 fetcher/options 保存在 ref 中,讓 refetch 即使在呼叫端
|
||||
// 傳入行內函式與物件字面值時也能保持參照穩定。
|
||||
// 若沒有這麼做,每次渲染都會建立新的 refetch,下方的 effect 會在
|
||||
// 每次狀態更新後重新執行,造成無限取得迴圈。
|
||||
const fetcherRef = useRef(fetcher)
|
||||
const optionsRef = useRef(options)
|
||||
useEffect(() => {
|
||||
fetcherRef.current = fetcher
|
||||
optionsRef.current = options
|
||||
})
|
||||
|
||||
const refetch = useCallback(async () => {
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
|
||||
try {
|
||||
const result = await fetcher()
|
||||
const result = await fetcherRef.current()
|
||||
setData(result)
|
||||
options?.onSuccess?.(result)
|
||||
optionsRef.current?.onSuccess?.(result)
|
||||
} catch (err) {
|
||||
const error = err as Error
|
||||
setError(error)
|
||||
options?.onError?.(error)
|
||||
optionsRef.current?.onError?.(error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}, [fetcher, options])
|
||||
}, [])
|
||||
|
||||
const enabled = options?.enabled !== false
|
||||
|
||||
useEffect(() => {
|
||||
if (options?.enabled !== false) {
|
||||
if (enabled) {
|
||||
refetch()
|
||||
}
|
||||
}, [key, refetch, options?.enabled])
|
||||
}, [key, enabled, refetch])
|
||||
|
||||
return { data, error, loading, refetch }
|
||||
}
|
||||
@@ -284,8 +297,9 @@ export function useMarkets() {
|
||||
|
||||
```typescript
|
||||
// PASS: useMemo 用於昂貴計算
|
||||
// 排序前先複製 - Array.prototype.sort 會就地修改陣列
|
||||
const sortedMarkets = useMemo(() => {
|
||||
return markets.sort((a, b) => b.volume - a.volume)
|
||||
return [...markets].sort((a, b) => b.volume - a.volume)
|
||||
}, [markets])
|
||||
|
||||
// PASS: useCallback 用於傳遞給子元件的函式
|
||||
|
||||
Reference in New Issue
Block a user