You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Relay Modern的FragmentContainer中注入postId变量

解决Relay Modern中从Props注入FragmentContainer变量的问题

我明白你现在的困境——想把从URL获取的postId注入到PostDetail的Fragment里,而不是依赖硬编码的defaultValue。这是Relay Modern中传递Fragment参数的典型场景,咱们一步步来解决:

核心问题分析

你的Fragment定义了必填的$postId参数,但父组件的查询在引用...PostDetail_viewer时,既没有声明这个变量,也没有把变量传递给Fragment,导致Relay编译器找不到变量值而报错。咱们需要把postId从父组件的props传递到Relay查询,再传递给Fragment。

具体修改步骤

1. 修改父组件singlePost.js的查询,声明并传递变量

首先要在父查询中定义$postId变量,并且通过@arguments指令把变量传递给Fragment:

import React, { Component } from 'react'
import { graphql } from 'react-relay'
import withData from '_libs/withData'
import PostDetail from '_components/post_page/PostDetail'
import App from '_components/App'

class PostsPage extends Component {
  static displayName = `PostsPage`
  
  static getInitialProps ({ query }) {
    // 从URL query中提取postId并返回
    return { query, postId: query.postId }
  }

  render () {
    const { viewer } = this.props
    return (
      <div>
        {viewer ? <PostDetail viewer={viewer} /> : 'no viewer'}
      </div>
    )
  }
}

export default withData(PostsPage, {
  query: graphql`
    query singlePost_Query($postId: String!) { # 声明必填的$postId变量
      viewer {
        # 通过@arguments把变量传递给Fragment
        ...PostDetail_viewer @arguments(postId: $postId)
      }
    }
  `,
  // 把getInitialProps拿到的postId作为变量传递给Relay查询
  variables: ({ postId }) => ({ postId })
})

2. 修改postDetail.js的Fragment,移除defaultValue

现在可以安全移除defaultValue,因为变量会从父查询自动传递过来:

import React from 'react'
import PropTypes from 'prop-types'
import { createFragmentContainer, graphql } from 'react-relay'

const PostDetail = (props) => {
  // 现在可以直接从props.viewer.post获取对应的数据
  const { post } = props.viewer
  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.description}</p>
      <img src={post.image} alt={post.title} />
      <p>作者: {post.creator.firstName} {post.creator.lastName}</p>
    </div>
  )
}

PostDetail.propTypes = {
  viewer: PropTypes.shape({
    post: PropTypes.shape({
      title: PropTypes.string.isRequired,
      description: PropTypes.string.isRequired,
      image: PropTypes.string.isRequired,
      creator: PropTypes.shape({
        firstName: PropTypes.string.isRequired,
        lastName: PropTypes.string.isRequired,
      }).isRequired,
    }).isRequired,
  }).isRequired,
}

export default createFragmentContainer(
  PostDetail,
  graphql`
    fragment PostDetail_viewer on Viewer @argumentDefinitions(
      postId: {type: "String!"}, # 移除defaultValue,保持必填声明
    ) {
      post (postId: $postId) {
        title
        description
        image
        creator {
          firstName
          lastName
        }
      }
    }
  `,
)

关键说明

  • 父查询必须显式声明Fragment需要的变量,再通过@arguments指令把变量传递给Fragment,这是Relay传递参数的标准方式。
  • 通过withData的variables配置项,把从getInitialProps获取的postId注入到Relay查询中。
  • 不需要在PostDetail组件中手动传递postId,Relay会自动根据Fragment参数获取对应数据,并注入到props.viewer里。

这样修改后,Relay就能正确从URL的query参数中获取postId,并传递给Fragment,你就可以摆脱硬编码的defaultValue了。

内容的提问来源于stack exchange,提问作者user6198643

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:18:52