搜索

PythonReactSEOPDF
GitHub Skill

scaffold-context

Scaffold a new React Context module inside an existing feature using the Context + useReducer pattern (state, actions, reducer, context, provider, and barrel exports).

mcgaryes☆ 0 仓库 Stars0 仓库 Forks

安装与使用

请根据来源仓库和你的 AI 工具说明安装此技能。先阅读技能文件和依赖要求,再添加到工作流。

查看来源 ↗使用指南

技能说明

Scaffold Context

Scaffold a new React Context module within an existing feature, following the Context + useReducer pattern.

Usage

/scaffold-context <context-name>

Example: /scaffold-context voice-recorder

Instructions

Follow these steps to scaffold a new context:

Step 1: Parse Context Name

The context name is provided in $ARGUMENTS. If $ARGUMENTS is empty or missing, use AskUserQuestion to prompt:

What is the name of the context? (use kebab-case, e.g., voice-recorder)
Step 2: Validate Context Name

Ensure the context name:

  • Uses kebab-case (lowercase letters and hyphens only)
  • Does not start or end with a hyphen
  • Is not empty

If invalid, inform the user and ask for a valid name.

Step 3: Select Target Feature

List all existing features by scanning features/ directory.

If no features exist, inform the user they need to create a feature first using /scaffold-feature.

If only one feature exists, confirm with the user that they want to add the context to that feature.

If multiple features exist, use AskUserQuestion to ask which feature to add the context to:

Question: "Which feature should this context belong to?" Header: "Feature" Options: List existing feature names (up to 4). If more than 4 features exist, show the 4 most recently modified and include guidance to specify "Other" for unlisted features.

Step 4: Ensure Contexts Directory Exists

Check if features/{feature-name}/contexts/ directory exists. If not, create it along with an index.ts barrel file:

contexts/index.ts:

// {Feature Name} Contexts
//
// Add your React Context modules here. Each context should have its own directory:
//
// contexts/
// └── {context-name}/
//     ├── {context-name}-state.tsx    - State interface and initial values
//     ├── {context-name}-actions.tsx  - Action types and interfaces
//     ├── {context-name}-reducer.tsx  - Reducer function
//     ├── {context-name}-context.tsx  - React Context creation
//     └── {context-name}-provider.tsx - Provider component
Step 5: Generate Context Files

Create the context directory at features/{feature-name}/contexts/{context-name}/.

Generate the following 6 files:

{context-name}-state.tsx
export interface {ContextName}State {
  // Add your state properties here
  isLoading: boolean;
  error?: string;
}

export const {contextName}InitialState: {ContextName}State = {
  isLoading: false,
  error: undefined,
};
{context-name}-actions.tsx
export enum {ContextName}ActionType {
  setLoading = "SET_LOADING",
  setError = "SET_ERROR",
  reset = "RESET",
}

export interface SetLoadingAction {
  type: {ContextName}ActionType.setLoading;
  payload: boolean;
}

export interface SetErrorAction {
  type: {ContextName}ActionType.setError;
  payload: string | undefined;
}

export interface ResetAction {
  type: {ContextName}ActionType.reset;
}

export type {ContextName}Action =
  | SetLoadingAction
  | SetErrorAction
  | ResetAction;
{context-name}-reducer.tsx
import { type {ContextName}State, {contextName}InitialState } from "./{context-name}-state";
import { type {ContextName}Action, {ContextName}ActionType } from "./{context-name}-actions";

export function {contextName}Reducer(
  state: {ContextName}State,
  action: {ContextName}Action
): {ContextName}State {
  switch (action.type) {
    case {ContextName}ActionType.setLoading:
      return {
        ...state,
        isLoading: action.payload,
      };

    case {ContextName}ActionType.setError:
      return {
        ...state,
        error: action.payload,
        isLoading: false,
      };

    case {ContextName}ActionType.reset:
      return {contextName}InitialState;

    default:
      return state;
  }
}
{context-name}-context.tsx
import { createContext, type Dispatch } from "react";
import { type {ContextName}State, {contextName}InitialState } from "./{context-name}-state";
import { type {ContextName}Action } from "./{context-name}-actions";

export const {ContextName}Context = createContext<{
  state: {ContextName}State;
  dispatch: Dispatch<{ContextName}Action>;
}>({
  state: {contextName}InitialState,
  dispatch: () => {},
});
{context-name}-provider.tsx
"use client";

import { useReducer, type ReactNode } from "react";
import { {ContextName}Context } from "./{context-name}-context";
import { {contextName}Reducer } from "./{context-name}-reducer";
import { type {ContextName}State, {contextName}InitialState } from "./{context-name}-state";

export interface {ContextName}ProviderProps {
  children: ReactNode;
  initialState?: Partial<{ContextName}State>;
}

export function {ContextName}Provider(props: {ContextName}ProviderProps) {
  const { children, initialState } = props;
  const [state, dispatch] = useReducer(
    {contextName}Reducer,
    { ...{contextName}InitialState, ...initialState }
  );

  return (
    <{ContextName}Context.Provider value={{ state, dispatch }}>
      {children}
    </{ContextName}Context.Provider>
  );
}
index.ts
export { {ContextName}Context } from "./{context-name}-context";
export { {ContextName}Provider } from "./{context-name}-provider";
export type { {ContextName}ProviderProps } from "./{context-name}-provider";
export { {contextName}Reducer } from "./{context-name}-reducer";
export { type {ContextName}State, {contextName}InitialState } from "./{context-name}-state";
export {
  {ContextName}ActionType,
  type {ContextName}Action,
  type SetLoadingAction,
  type SetErrorAction,
  type ResetAction,
} from "./{context-name}-actions";
Step 6: Output Summary

After creating all files, output a summary:

Created context: {context-name} in {feature-name}

features/{feature-name}/contexts/{context-name}/
├── {context-name}-state.tsx
├── {context-name}-actions.tsx
├── {context-name}-reducer.tsx
├── {context-name}-context.tsx
├── {context-name}-provider.tsx
└── index.ts

Next steps:
1. Define your state properties in {context-name}-state.tsx
2. Add action types and interfaces in {context-name}-actions.tsx
3. Implement state transitions in {context-name}-reducer.tsx
4. Create a custom hook in hooks/ for convenient context access:

   // hooks/use-{context-name}.ts
   export function use{ContextName}() {
     const { state, dispatch } = useContext({ContextName}Context);
     // Add helper methods that wrap dispatch calls
     return { ...state, /* methods */ };
   }

Naming Conventions

  • context-name: kebab-case (e.g., voice-recorder)
  • ContextName: PascalCase (e.g., VoiceRecorder)
  • contextName: camelCase (e.g., voiceRecorder)

Convert kebab-case to other cases:

Input (kebab) PascalCase camelCase
voice-recorder VoiceRecorder voiceRecorder
user-auth UserAuth userAuth

Conversion rules:

  1. Split on hyphens
  2. For PascalCase: capitalize first letter of each word, join without separators
  3. For camelCase: lowercase first word, capitalize first letter of subsequent words, join without separators

使用示例

查看来源仓库中的使用示例与配置说明。

查看来源 ↗

来源历史

收录时间
2026-01-20
索引更新时间
2026-01-26
Branch
main

收录与同步日期属于本站记录。源码修改历史请查看来源仓库。

GitHub ↗

chat Comments (0)

chat_bubble_outline

No comments yet. Be the first to share your thoughts!