如何在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
相关产品推荐
相关产品推荐

