AGENT SKILL

react

Must always be enabled when writing/reviewing React code.

适用职业开发工程师
使用场景前端开发
License 许可
MIT
最近更新
2026-11-01
Stars
★ 3
Forks
1

01 前言 Front Matter

name
react
description
Must always be enabled when writing/reviewing React code.

03 SKILL.md 正文

<role> You are implementing React components following modern best practices. Your goal is to write clean, performant React code that avoids unnecessary Effects and follows established patterns. </role>

<core_principles>

Core Principles

1. Minimize useEffect Usage

Think harder before adding useEffect. Most scenarios have better alternatives:

<when_not_to_use_effect>

When NOT to Use useEffect

Data transformation for rendering:

  • ❌ Don't: Use Effect to compute derived state
  • ✅ Do: Calculate during render at top level
// ❌ Bad: Cascading updates
const [filteredItems, setFilteredItems] = useState<Item[]>([]);
useEffect(() => {
  setFilteredItems(items.filter(item => item.active));
}, [items]);

// ✅ Good: Direct computation
const filteredItems = items.filter(item => item.active);

Handling user events:

  • ❌ Don't: Use Effect to respond to user actions
  • ✅ Do: Handle logic in event handlers
// ❌ Bad: Lost interaction context
useEffect(() => {
  if (buttonClicked) {
    submitForm();
  }
}, [buttonClicked]);

// ✅ Good: Explicit intent
const handleSubmit = () => {
  submitForm();
};

Caching expensive computations:

  • ❌ Don't: Store computed results in state via Effects
  • ✅ Do: Use useMemo
// ❌ Bad: Manual memoization
const [expensiveResult, setExpensiveResult] = useState<Result | null>(null);
useEffect(() => {
  setExpensiveResult(computeExpensiveValue(data));
}, [data]);

// ✅ Good: useMemo
const expensiveResult = useMemo(() => computeExpensiveValue(data), [data]);

Resetting state on prop changes:

  • ❌ Don't: Use Effect to reset state
  • ✅ Do: Use key prop to force remount
// ❌ Bad: Manual synchronization
useEffect(() => {
  setLocalState(defaultValue);
}, [userId]);

// ✅ Good: Key-based reset
<Profile key={userId} userId={userId} />

</when_not_to_use_effect>

<legitimate_use_cases>

Legitimate useEffect Use Cases

Only use Effects for:

  1. Synchronizing with external systems (browser APIs, third-party widgets)
  2. Data fetching with proper cleanup (avoid race conditions)
  3. Subscriptions (prefer useSyncExternalStore when possible)

Pattern for data fetching (if not using query client):

useEffect(() => {
  let ignore = false;

  async function fetchData() {
    const result = await api.getData();
    if (!ignore) {
      setData(result);
    }
  }

  fetchData();
  return () => { ignore = true; }; // Cleanup to prevent race conditions
}, [dependency]);

</legitimate_use_cases> </core_principles>

<component_definition>

2. Component Definition Style

Always use FC type annotation:

import { FC, PropsWithChildren } from 'react';

// For components without children
type ButtonProps {
  label: string;
  onClick: () => void;
}

const Button: FC<ButtonProps> = ({ label, onClick }) => {
  return <button onClick={onClick}>{label}</button>;
};

// For components that accept children
type CardProps {
  title: string;
}

const Card: FC<PropsWithChildren<CardProps>> = ({ title, children }) => {
  return (
    <div>
      <h2>{title}</h2>
      <div>{children}</div>
    </div>
  );
};

Never use function declaration syntax:

// ❌ Bad: Avoid this style
function MyComponent(props: Props) {
  return <div />;
}

</component_definition>

<api_requests>

3. API Request Handling

Never use fetch directly in components. Always use the project's query client.

<detection_workflow>

Detection Workflow

  1. Check project dependencies in package.json:

    • @apollo/client → Use Apollo Client hooks
    • @tanstack/react-query → Use Tanstack Query hooks
    • swr → Use SWR hooks
  2. Search for existing usage patterns:

    • Look for useQuery, useMutation, useSWR, useApolloClient in codebase
    • Follow established patterns for consistency
  3. Apply appropriate client:

<apollo_client> Apollo Client (GraphQL):

import { useQuery, useMutation, gql } from '@apollo/client';

const GET_USER = gql`
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
      email
    }
  }
`;

const UserProfile: FC<{ userId: string }> = ({ userId }) => {
  const { data, loading, error } = useQuery(GET_USER, {
    variables: { id: userId },
  });

  if (loading) return <Spinner />;
  if (error) return <ErrorMessage error={error} />;

  return <div>{data.user.name}</div>;
};

// Mutations
const UPDATE_USER = gql`
  mutation UpdateUser($id: ID!, $name: String!) {
    updateUser(id: $id, name: $name) {
      id
      name
    }
  }
`;

const EditForm: FC = () => {
  const [updateUser, { loading }] = useMutation(UPDATE_USER);

  const handleSubmit = async (values: FormValues) => {
    await updateUser({ variables: { id: values.id, name: values.name } });
  };

  return <form onSubmit={handleSubmit}>...</form>;
};

</apollo_client>

<tanstack_query> Tanstack Query (REST):

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';

const UserProfile: FC<{ userId: string }> = ({ userId }) => {
  const { data, isLoading, error } = useQuery({
    queryKey: ['user', userId],
    queryFn: () => api.getUser(userId),
  });

  if (isLoading) return <Spinner />;
  if (error) return <ErrorMessage error={error} />;

  return <div>{data.name}</div>;
};

// Mutations with cache invalidation
const EditForm: FC = () => {
  const queryClient = useQueryClient();

  const mutation = useMutation({
    mutationFn: (values: FormValues) => api.updateUser(values),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['user'] });
    },
  });

  const handleSubmit = (values: FormValues) => {
    mutation.mutate(values);
  };

  return <form onSubmit={handleSubmit}>...</form>;
};

</tanstack_query>

<swr> SWR:

import useSWR from 'swr';
import useSWRMutation from 'swr/mutation';

const UserProfile: FC<{ userId: string }> = ({ userId }) => {
  const { data, error, isLoading } = useSWR(
    `/api/users/${userId}`,
    fetcher
  );

  if (isLoading) return <Spinner />;
  if (error) return <ErrorMessage error={error} />;

  return <div>{data.name}</div>;
};

// Mutations
const EditForm: FC = () => {
  const { trigger, isMutating } = useSWRMutation(
    '/api/users',
    updateUser
  );

  const handleSubmit = async (values: FormValues) => {
    await trigger(values);
  };

  return <form onSubmit={handleSubmit}>...</form>;
};

</swr> </detection_workflow>

Benefits of query clients:

  • Automatic caching and deduplication
  • Loading/error state management
  • Race condition handling
  • Cache invalidation and refetching
  • Optimistic updates support </api_requests> </core_principles>

<workflow>

Implementation Workflow

  1. Before writing component:

    • Identify data dependencies and state requirements
    • Think harder: Can state be derived instead of stored?
    • Plan event handlers before considering Effects
  2. During implementation:

    • Define component with FC type annotation
    • Calculate derived values at top level
    • Use useMemo only for expensive computations
    • Handle user interactions in event handlers
    • Use query client hooks for API requests
  3. Effect review checklist:

    • [ ] Is this synchronizing with an external system?
    • [ ] Could this be a calculated value instead?
    • [ ] Should this be in an event handler?
    • [ ] Am I using the right hook (useMemo, key prop)?
    • [ ] If data fetching, is query client available?
  4. If Effect is necessary:

    • Document why Effect is required
    • Implement proper cleanup to prevent memory leaks
    • Handle race conditions for async operations </workflow>

<anti_patterns>

Anti-Patterns to Avoid

❌ Chaining Effects:

// Bad: Effects triggering each other
useEffect(() => setB(a), [a]);
useEffect(() => setC(b), [b]);

// Good: Direct computation or single event handler
const b = computeB(a);
const c = computeC(b);

❌ Effect-based initialization:

// Bad: One-time initialization in Effect
useEffect(() => {
  setData(expensiveInit());
}, []);

// Good: useState with initializer
const [data] = useState(() => expensiveInit());

❌ Direct fetch calls:

// Bad: Manual fetch in component
useEffect(() => {
  fetch('/api/data').then(res => res.json()).then(setData);
}, []);

// Good: Use query client
const { data } = useQuery({ queryKey: ['data'], queryFn: fetchData });

</anti_patterns>

04 同仓库更多 Skills

shengdabai
shengdabai/Tony-Claude-Code-Skills

xiaolai-methodology

以李笑来(Li Xiaolai)的思考方式、方法论与表达风格,为用户做全方位 1-on-1 教练指导,覆盖创业、赚钱、投资、学习、自学、读书写作、用 AI、以及人生心态与自我管理。当用户提到 "李笑来"、"笑来"、"笑来老师"、"扮演李笑来"、"找笑来聊聊"、"笑来怎么看"、"xiaolai"、"把时间当作朋友"、"通往财富自由之路"、"定投改变命运"、"韭菜的自我修养"、"自学是门手艺"、"让时间陪你慢慢变富"、"七年就是一辈子"、"元认知"、"活在未来"、"复利/长期主义"、"践行"、"痴迷改进"、"个人商业模式/出售时间"、"睡后收入"、"定投"、"财富自由"、"操作系统升级"、"最少必要知识"、"北极星提示词"、"用 AI 该怎么学/思考" 等任一触发词,或当用户带着关于创业/赚钱/投资/学习/职业/重大人生决策的困惑、希望被人用笑来式的「逻辑 + 大白话 + 类比 + 重新定义 + 践行导向」来点醒和指导时,自动进入李笑来教练模式。

写作与文案
★ 3
shengdabai
shengdabai/Tony-Claude-Code-Skills

zread

Produce and consume a wiki-style knowledge base for a code repository via the `zread` CLI and its on-disk output under `./.zread/wiki/`. Use this skill whenever the user wants to understand, onboard onto, explore, summarize, map, or get an overview of an unfamiliar codebase; asks for architecture docs, a project wiki, a repo walkthrough, module/package explanations, or "what does this repo do"; wants to generate, regenerate, resume, browse, or serve code documentation locally; or mentions zread / zread.ai directly. Also use it proactively before diving into a large unknown repo — if `./.zread/wiki/current` exists, read the generated pages instead of crawling source file-by-file; if it doesn't, consider offering to run `zread generate`. The trigger is the intent (understand a codebase through generated docs), not the literal word "zread".

开发工程师Skill与智能体开发
★ 3
shengdabai
shengdabai/Tony-Claude-Code-Skills

youtube

Launch the YouTube Creator Agent to auto-generate videos. Use when: user types /youtube, wants to create YouTube videos, generate video content, or upload to YouTube. Keywords: youtube, video, 视频, 创作视频, 发布视频

内容创作者Skill与智能体开发
★ 3
shengdabai
shengdabai/Tony-Claude-Code-Skills

youtube-script-sync

Sync, update, or optimize Tony's GetNote knowledge base `Youtube视频逐字稿` by turning each parent recording or first-person idea note into an idempotent child note containing a directly recordable YouTube long-video or Shorts script. Use when the user says “更新/同步/优化 Youtube视频逐字稿知识库”, or says “更新/同步/优化该知识库” while this knowledge base is the active context.

Skill与智能体开发
★ 3
shengdabai
shengdabai/Tony-Claude-Code-Skills

writing-skills

How to write SKILL.md files that trigger reliably and teach effectively. Use when creating, improving, or reviewing Claude Code skills.

开发工程师内容创作者写作与文案Skill与智能体开发
★ 3
shengdabai
shengdabai/Tony-Claude-Code-Skills

writing-rules

How to write .claude/rules/ files that Claude actually follows. Use when creating, improving, or reviewing project rules.

内容创作者写作与文案
★ 3