Token导航 LogoToken导航TokenDH.com
研究检索需要联网github未标认证来源可访问clear审计通过

relay-fragments-patterns中继片段模式

Agent Skill

relay-fragments-patterns 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

857

周安装

35

GitHub Stars

142

下载量

277
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

3

许可证

MIT

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:relay-fragments-patterns(中继片段模式)
来源仓库:https://github.com/thebushidocollective/han
仓库路径:skills/relay-fragments-patterns
安装命令:
npx skills add https://github.com/thebushidocollective/han --skill relay-fragments-patterns
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/thebushidocollective/han --skill relay-fragments-patterns

简介

relay-fragments-patterns 用于查找、检索和筛选相关信息。

  • 适合在 Codex、Claude、Cursor、Gemini CLI 中根据关键词或任务场景快速定位候选结果。
  • 通过 npx skills add 命令从指定 GitHub 仓库安装并使用。
  • 安装前需确认权限范围、维护状态,注意是否触发联网、命令执行或文件读写操作。
  • 适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

SKILL.md

Relay Fragments Patterns

Master Relay's fragment composition for building maintainable React applications with proper data dependencies and component colocation.

Overview

Relay fragments enable component-level data declaration with automatic composition, data masking, and optimal data fetching. Fragments colocate data requirements with components for better maintainability.

Installation and Setup

Installing Relay

# Install Relay packages
npm install react-relay relay-runtime

# Install Relay compiler
npm install --save-dev relay-compiler babel-plugin-relay

# Install GraphQL
npm install graphql

Relay Configuration

// relay.config.js
module.exports = {
  src: './src',
  schema: './schema.graphql',
  exclude: ['**/node_modules/**', '**/__mocks__/**', '**/__generated__/**'],
  language: 'typescript',
  artifactDirectory: './src/__generated__'
};

// package.json
{
  "scripts": {
    "relay": "relay-compiler",
    "relay:watch": "relay-compiler --watch"
  }
}

Environment Setup

// RelayEnvironment.js
import {
  Environment,
  Network,
  RecordSource,
  Store
} from 'relay-runtime';

function fetchQuery(operation, variables) {
  return fetch('http://localhost:4000/graphql', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${localStorage.getItem('token')}`
    },
    body: JSON.stringify({
      query: operation.text,
      variables
    })
  }).then(response => response.json());
}

const environment = new Environment({
  network: Network.create(fetchQuery),
  store: new Store(new RecordSource())
});

export default environment;

Core Patterns

1. Basic Fragment Definition

// PostCard.jsx
import { graphql, useFragment } from 'react-relay';

const PostCardFragment = graphql`
  fragment PostCard_post on Post {
    id
    title
    excerpt
    publishedAt
    author {
      name
      avatar
    }
  }
`;

function PostCard({ post }) {
  const data = useFragment(PostCardFragment, post);

  return (
    <article>
      <h2>{data.title}</h2>
      <p>{data.excerpt}</p>
      <div>
        <img src={data.author.avatar} alt={data.author.name} />
        <span>{data.author.name}</span>
      </div>
      <time>{data.publishedAt}</time>
    </article>
  );
}

export default PostCard;

2. Fragment Composition

// UserProfile.jsx
const UserProfileFragment = graphql`
  fragment UserProfile_user on User {
    id
    name
    bio
    ...UserAvatar_user
    ...UserStats_user
  }
`;

function UserProfile({ user }) {
  const data = useFragment(UserProfileFragment, user);

  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.bio}</p>
      <UserAvatar user={data} />
      <UserStats user={data} />
    </div>
  );
}

// UserAvatar.jsx
const UserAvatarFragment = graphql`
  fragment UserAvatar_user on User {
    name
    avatar
    isOnline
  }
`;

function UserAvatar({ user }) {
  const data = useFragment(UserAvatarFragment, user);

  return (
    <div className="avatar-container">
      <img src={data.avatar} alt={data.name} />
      {data.isOnline && <span className="online-indicator" />}
    </div>
  );
}

// UserStats.jsx
const UserStatsFragment = graphql`
  fragment UserStats_user on User {
    postsCount
    followersCount
    followingCount
  }
`;

function UserStats({ user }) {
  const data = useFragment(UserStatsFragment, user);

  return (
    <div className="stats">
      <div>Posts: {data.postsCount}</div>
      <div>Followers: {data.followersCount}</div>
      <div>Following: {data.followingCount}</div>
    </div>
  );
}

3. Fragment Arguments

// Post.jsx
const PostFragment = graphql`
  fragment Post_post on Post
  @argumentDefinitions(
    includeComments: { type: "Boolean!", defaultValue: false }
    commentsFirst: { type: "Int", defaultValue: 10 }
  ) {
    id
    title
    body
    comments(first: $commentsFirst) @include(if: $includeComments) {
      edges {
        node {
          ...Comment_comment
        }
      }
    }
  }
`;

function Post({ post, showComments = false }) {
  const data = useFragment(
    PostFragment,
    post,
    {
      includeComments: showComments,
      commentsFirst: 20
    }
  );

  return (
    <article>
      <h1>{data.title}</h1>
      <div>{data.body}</div>
      {showComments && (
        <CommentsList comments={data.comments.edges.map(e => e.node)} />
      )}
    </article>
  );
}

4. Data Masking

// Parent component
const ParentFragment = graphql`
  fragment Parent_data on Query {
    user {
      id
      ...Child_user
    }
  }
`;

function Parent({ data }) {
  const parentData = useFragment(ParentFragment, data);

  // parentData.user only contains id and fragment reference
  // Cannot access user.name here (data masking)

  return (
    <div>
      <h1>User ID: {parentData.user.id}</h1>
      <Child user={parentData.user} />
    </div>
  );
}

// Child component
const ChildFragment = graphql`
  fragment Child_user on User {
    name
    email
    avatar
  }
`;

function Child({ user }) {
  const data = useFragment(ChildFragment, user);

  // Only Child can access name, email, avatar
  return (
    <div>
      <h2>{data.name}</h2>
      <p>{data.email}</p>
      <img src={data.avatar} alt={data.name} />
    </div>
  );
}

5. Fragment with Connections

// PostsList.jsx
const PostsListFragment = graphql`
  fragment PostsList_query on Query
  @argumentDefinitions(
    first: { type: "Int", defaultValue: 10 }
    after: { type: "String" }
  )
  @refetchable(queryName: "PostsListRefetchQuery") {
    posts(first: $first, after: $after)
    @connection(key: "PostsList_posts") {
      edges {
        node {
          id
          ...PostCard_post
        }
      }
    }
  }
`;

function PostsList({ query }) {
  const { data, loadNext, hasNext, isLoadingNext } = usePaginationFragment(
    PostsListFragment,
    query
  );

  return (
    <div>
      {data.posts.edges.map(({ node }) => (
        <PostCard key={node.id} post={node} />
      ))}

      {hasNext && (
        <button
          onClick={() => loadNext(10)}
          disabled={isLoadingNext}
        >
          {isLoadingNext ? 'Loading...' : 'Load More'}
        </button>
      )}
    </div>
  );
}

6. Refetchable Fragments

// UserProfile.jsx
const UserProfileFragment = graphql`
  fragment UserProfile_user on User
  @refetchable(queryName: "UserProfileRefetchQuery") {
    id
    name
    bio
    posts(first: 10) {
      edges {
        node {
          id
          title
        }
      }
    }
  }
`;

function UserProfile({ user }) {
  const [data, refetch] = useRefetchableFragment(
    UserProfileFragment,
    user
  );

  const handleRefresh = () => {
    refetch({}, { fetchPolicy: 'network-only' });
  };

  return (
    <div>
      <button onClick={handleRefresh}>Refresh</button>
      <h1>{data.name}</h1>
      <p>{data.bio}</p>
      <PostsList posts={data.posts.edges} />
    </div>
  );
}

7. Plural Fragments

// PostsList.jsx
const PostsListFragment = graphql`
  fragment PostsList_posts on Post @relay(plural: true) {
    id
    title
    excerpt
  }
`;

function PostsList({ posts }) {
  const data = useFragment(PostsListFragment, posts);

  return (
    <div>
      {data.map(post => (
        <article key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.excerpt}</p>
        </article>
      ))}
    </div>
  );
}

// Usage
const query = graphql`
  query PostsQuery {
    posts {
      ...PostsList_posts
    }
  }
`;

8. Conditional Fragments

// Content.jsx
const ContentFragment = graphql`
  fragment Content_content on Content {
    __typename
    ... on Post {
      title
      body
      author {
        name
      }
    }
    ... on Video {
      title
      duration
      thumbnailUrl
      creator {
        name
      }
    }
    ... on Image {
      title
      imageUrl
      photographer {
        name
      }
    }
  }
`;

function Content({ content }) {
  const data = useFragment(ContentFragment, content);

  switch (data.__typename) {
    case 'Post':
      return (
        <article>
          <h2>{data.title}</h2>
          <p>{data.body}</p>
          <span>By {data.author.name}</span>
        </article>
      );

    case 'Video':
      return (
        <div>
          <video src={data.thumbnailUrl} />
          <h2>{data.title}</h2>
          <span>Duration: {data.duration}s</span>
          <span>By {data.creator.name}</span>
        </div>
      );

    case 'Image':
      return (
        <figure>
          <img src={data.imageUrl} alt={data.title} />
          <figcaption>
            {data.title} by {data.photographer.name}
          </figcaption>
        </figure>
      );

    default:
      return null;
  }
}

9. Fragment Containers Legacy Pattern

// Legacy container pattern (v1-11)
import { createFragmentContainer, graphql } from 'react-relay';

class PostCard extends React.Component {
  render() {
    const { post } = this.props;
    return (
      <article>
        <h2>{post.title}</h2>
        <p>{post.excerpt}</p>
      </article>
    );
  }
}

export default createFragmentContainer(PostCard, {
  post: graphql`
    fragment PostCard_post on Post {
      id
      title
      excerpt
    }
  `
});

// Modern hooks pattern (v12+)
function PostCard({ post }) {
  const data = useFragment(
    graphql`
      fragment PostCard_post on Post {
        id
        title
        excerpt
      }
    `,
    post
  );

  return (
    <article>
      <h2>{data.title}</h2>
      <p>{data.excerpt}</p>
    </article>
  );
}

10. Advanced Fragment Patterns

// Recursive fragments
const CommentFragment = graphql`
  fragment Comment_comment on Comment {
    id
    body
    author {
      name
    }
    replies(first: 5) {
      edges {
        node {
          ...Comment_comment
        }
      }
    }
  }
`;

function Comment({ comment, depth = 0 }) {
  const data = useFragment(CommentFragment, comment);

  if (depth > 3) return null; // Prevent infinite recursion

  return (
    <div style={{ marginLeft: depth * 20 }}>
      <p>{data.body}</p>
      <span>{data.author.name}</span>

      {data.replies?.edges.map(({ node }) => (
        <Comment key={node.id} comment={node} depth={depth + 1} />
      ))}
    </div>
  );
}

// Fragment with inline data
const PostWithInlineFragment = graphql`
  fragment PostWithInline_post on Post {
    id
    title
    author {
      ... on User {
        id
        name
        isVerified
      }
      ... on Organization {
        id
        name
        type
      }
    }
  }
`;

// Fragment with directives
const ConditionalFragment = graphql`
  fragment Conditional_post on Post
  @argumentDefinitions(
    includeLikes: { type: "Boolean!", defaultValue: false }
    includeComments: { type: "Boolean!", defaultValue: true }
  ) {
    id
    title
    likesCount @include(if: $includeLikes)
    comments(first: 10) @include(if: $includeComments) {
      edges {
        node {
          id
          body
        }
      }
    }
  }
`;

// Fragment with required fields
const RequiredFieldsFragment = graphql`
  fragment RequiredFields_user on User {
    id
    name @required(action: LOG)
    email @required(action: THROW)
    avatar @required(action: NONE)
  }
`;

Best Practices

  1. Colocate fragments with components - Keep data requirements together
  2. Use fragment composition - Build complex queries from simple fragments
  3. Leverage data masking - Prevent tight coupling between components
  4. Define minimal fragments - Request only necessary fields
  5. Use arguments for flexibility - Make fragments reusable
  6. Follow naming conventions - ComponentName_propName pattern
  7. Avoid circular dependencies - Design fragment hierarchy carefully
  8. Use refetchable fragments - Enable component-level refetching
  9. Handle loading states - Provide feedback during data fetches
  10. Type fragments properly - Ensure type safety with TypeScript

Common Pitfalls

  1. Fragment overfetching - Requesting unnecessary fields
  2. Missing data masking - Accessing non-declared fields
  3. Circular fragment references - Creating dependency cycles
  4. Improper fragment composition - Not spreading child fragments
  5. Hardcoded values - Not using fragment arguments
  6. Breaking data contracts - Changing fragment fields carelessly
  7. Missing fragment keys - Not providing unique keys in lists
  8. Ignoring type conditions - Not handling union types properly
  9. Excessive nesting - Creating overly deep fragment hierarchies
  10. Poor error handling - Not handling missing data gracefully

When to Use

  • Building React applications with GraphQL
  • Implementing component-driven architecture
  • Creating reusable UI components
  • Developing data-intensive applications
  • Building social media platforms
  • Creating e-commerce applications
  • Implementing collaborative tools
  • Developing content management systems
  • Building admin dashboards
  • Creating mobile applications with React Native

Resources

适合场景

01

研究助手

02

事实核查

03

知识库问答

04

带来源的搜索总结

能力概览

能力 1

组合搜索和大模型调用

能力 2

支持多来源检索和总结

能力 3

强调引用来源和事实核查

能力 4

适合研究型 Agent 流程

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

OpenCode

26.17%
按下载量换算72

Claude Code

22.56%
按下载量换算62

Codex

20.19%
按下载量换算56

windsurf

13.76%
按下载量换算38

Antigravity

8.08%
按下载量换算22

Cursor

3.51%
按下载量换算10

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。

来源信息

继续浏览同类 Skills