admin管理员组文章数量:1287778
I'm having some issues setting up a refetchContainer in Relay Modern. A parent ponent is the QueryRenderer, which runs an initial query, populating the child ponent's props appropriately (a-prop-riately? eh? eh?!) . The refetchContainer specifies all our variables, and on an input field's onChange event, re-runs a query with the new variables. This all works perfectly, except that the child's props are never updated with the new data received. I can drill down the Relay store and see that the query was indeed received with the appropriate data. Been bangin' my head against this for a while and I would appreciate some help. Probably something simple I'm missing. And Lord knows Relay Modern documentation is sparse.
I've poked around and can't find an appropriate solution. This guy seems to be having a similar issue: relay refetch doesn't show the result
The parent ponent with QueryRenderer:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { graphql, QueryRenderer } from 'react-relay';
import Search from './Search';
const propTypes = {
auth: PropTypes.object.isRequired,
};
class SearchContainer extends Component {
render() {
return (
<QueryRenderer
query={graphql`
query SearchContainerQuery($search: String!){
users: searchUsers(search:$search, first:10){
...Search_users
}
}`}
variables={{ search: 'someDefaultSearch' }}
environment={this.props.auth.environment}
render={({ error, props }) => {
if (error) {
console.log(error);
}
if (props) {
return <Search users={props.users} />;
}
return <div>No Dice</div>;
}}
/>
);
}
}
SearchContainer.propTypes = propTypes;
export default connect(state => ({ auth: state.auth }))(SearchContainer);
The child ponent with createRefetchContainer:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { createRefetchContainer, graphql } from 'react-relay';
const propTypes = {
relay: PropTypes.object.isRequired,
users: PropTypes.object,
};
const defaultProps = {
users: {},
};
class Search extends Component {
render() {
return (
<div>
<input
type="text"
onChange={(e) => {
e.preventDefault();
this.props.relay.refetch({
search: e.target.value,
});
}}
/>
<ul>
{this.props.users.nodes.map(user =>
<li key={user.id}>{user.username}</li>,
)}
</ul>
</div>
);
}
}
Search.propTypes = propTypes;
Search.defaultProps = defaultProps;
export default createRefetchContainer(
Search,
{
users: graphql.experimental`
fragment Search_users on SearchUsersConnection
@argumentDefinitions(
search: {type: "String", defaultValue: ""}
) {
nodes {
id
displayName
username
}
}
`,
},
graphql.experimental`
query SearchRefetchQuery($search: String!) {
users: searchUsers(search:$search, first:10){
...Search_users @arguments(search: $search)
}
}
`,
);
GraphQL looks like this:
# A connection to a list of `User` values.
type SearchUsersConnection {
# Information to aid in pagination.
pageInfo: PageInfo!
# The count of *all* `User` you could get from the connection.
totalCount: Int
# A list of edges which contains the `User` and cursor to aid in pagination.
edges: [SearchUsersEdge]
# A list of `User` objects.
nodes: [User]
}
Network calls are made appropriately, and data is returned as expected. NetworkCalls
It seems the @arguments directive can be left out of the refetch query here:
query SearchRefetchQuery($search: String!) {
users: searchUsers(search:$search, first:10){
...Search_users @arguments(search: $search)
}
}
(removing it seems to have no effect)
I've tried adding the @arguments directive to the parent ponent's fragment as per the remendation here: Pass variables to fragment container in relay modern, to no effect.
I'm having some issues setting up a refetchContainer in Relay Modern. A parent ponent is the QueryRenderer, which runs an initial query, populating the child ponent's props appropriately (a-prop-riately? eh? eh?!) . The refetchContainer specifies all our variables, and on an input field's onChange event, re-runs a query with the new variables. This all works perfectly, except that the child's props are never updated with the new data received. I can drill down the Relay store and see that the query was indeed received with the appropriate data. Been bangin' my head against this for a while and I would appreciate some help. Probably something simple I'm missing. And Lord knows Relay Modern documentation is sparse.
I've poked around and can't find an appropriate solution. This guy seems to be having a similar issue: relay refetch doesn't show the result
The parent ponent with QueryRenderer:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { graphql, QueryRenderer } from 'react-relay';
import Search from './Search';
const propTypes = {
auth: PropTypes.object.isRequired,
};
class SearchContainer extends Component {
render() {
return (
<QueryRenderer
query={graphql`
query SearchContainerQuery($search: String!){
users: searchUsers(search:$search, first:10){
...Search_users
}
}`}
variables={{ search: 'someDefaultSearch' }}
environment={this.props.auth.environment}
render={({ error, props }) => {
if (error) {
console.log(error);
}
if (props) {
return <Search users={props.users} />;
}
return <div>No Dice</div>;
}}
/>
);
}
}
SearchContainer.propTypes = propTypes;
export default connect(state => ({ auth: state.auth }))(SearchContainer);
The child ponent with createRefetchContainer:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { createRefetchContainer, graphql } from 'react-relay';
const propTypes = {
relay: PropTypes.object.isRequired,
users: PropTypes.object,
};
const defaultProps = {
users: {},
};
class Search extends Component {
render() {
return (
<div>
<input
type="text"
onChange={(e) => {
e.preventDefault();
this.props.relay.refetch({
search: e.target.value,
});
}}
/>
<ul>
{this.props.users.nodes.map(user =>
<li key={user.id}>{user.username}</li>,
)}
</ul>
</div>
);
}
}
Search.propTypes = propTypes;
Search.defaultProps = defaultProps;
export default createRefetchContainer(
Search,
{
users: graphql.experimental`
fragment Search_users on SearchUsersConnection
@argumentDefinitions(
search: {type: "String", defaultValue: ""}
) {
nodes {
id
displayName
username
}
}
`,
},
graphql.experimental`
query SearchRefetchQuery($search: String!) {
users: searchUsers(search:$search, first:10){
...Search_users @arguments(search: $search)
}
}
`,
);
GraphQL looks like this:
# A connection to a list of `User` values.
type SearchUsersConnection {
# Information to aid in pagination.
pageInfo: PageInfo!
# The count of *all* `User` you could get from the connection.
totalCount: Int
# A list of edges which contains the `User` and cursor to aid in pagination.
edges: [SearchUsersEdge]
# A list of `User` objects.
nodes: [User]
}
Network calls are made appropriately, and data is returned as expected. NetworkCalls
It seems the @arguments directive can be left out of the refetch query here:
query SearchRefetchQuery($search: String!) {
users: searchUsers(search:$search, first:10){
...Search_users @arguments(search: $search)
}
}
(removing it seems to have no effect)
I've tried adding the @arguments directive to the parent ponent's fragment as per the remendation here: Pass variables to fragment container in relay modern, to no effect.
Share Improve this question edited Sep 20, 2017 at 0:07 Tim 4,6715 gold badges39 silver badges44 bronze badges asked Jul 21, 2017 at 19:48 cntrlzcntrlz 1316 bronze badges 7- sorry not much help.. fwiw I have dropped refetchContainers pletely for simply passing new props to the QueryRenderer which gets the job done. example: github./NCI-GDC/portal-ui/blob/next/src/packages/@ncigdc/… – azium Commented Jul 21, 2017 at 20:34
- 1 @azium Yep, that seems to work just fine. It just bothers me that the refetchContainer, specifically designed for this, is so tricky to set up! – cntrlz Commented Jul 21, 2017 at 21:21
- I'm having the exact same issue and I am TOO banging my head on the wall :( – Mani Shooshtari Commented Nov 12, 2017 at 10:45
- I have an almost identical query working fine and can't find any apparent errors in your code. Did you try upgrading to a more recent version? ... or just maybe, try unwrapping it from redux just to see if it works on its own... – hisa_py Commented Nov 15, 2017 at 15:39
-
1
Oh I think I got through a similar problem too. If I remember correctly I believe the "id" Relay is using to identify the ponent is including the variables for the initial query so try unwrapping your container fragment in the QueryRenderer by moving the searchUsers(..) to the fragment and then in the query just ...Search_user. You'll have to define Search_user as a fragment of your root, i.e.: in my case it'd something like
fragment Search_user on RootQueryType
. My last suggestion is turning your debugger on and see whats going on when you get the data. – hisa_py Commented Dec 21, 2017 at 0:49
2 Answers
Reset to default 6As mentioned in other answers, this is actually expected behavior, and I'll try to expand on the answer a little bit.
When refetch is called and the refetchQuery
is executed, Relay doesn't actually use the result of the query to re-render the ponent. All it does is normalize the payload into the store and fire any relevant subscriptions. This means that if the fetched data is unrelated to the data that the mounted container is subscribed to (e.g. using a totally different node id that doesn't have any data overlaps), then the ponent won't re-render.
In this specific scenario, the reason why the container doesn't re-render, i.e. why it isn't subscribed to the changes fired by the refetchQuery
, is due to how subscriptions are set up. A subscription is basically a subscription to a snapshot
, which basically represents a concrete fragment and the data and records associated with it at a given point in time -- when the records associated with a snapshot change, the subscription for that snapshot will be notified of changes.
In this case, given that the fragment for the container has no variables, the snapshot that it will subscribe to will only be associated with the initial node; after refetch happens and the the store is updated, the records for the new node will have been updated, but the record associated with that original snapshot hasn't changed, so the container subscribed to it won't be notified.
This means that Refetch containers are only really meant to be used when you are changing variables in the ponent fragment. The solutions provided here are valid, i.e. including variables in the fragment for the refetch container or setting new variables one level up in the QueryRenderer.
This could definitely be made more clear in the docs, so I'll update them to reflect this. I hope this helps!
Oh I think I got through a similar problem. If I remember correctly I believe the "id" Relay is using to identify the ponent to pass the props to, is including the variables for the initial query so try unwrapping your container fragment from the QueryRenderer's query.
The setup that worked for me is something like the following:
<QueryRenderer
variables={{search: 'someDefaultSearch', count: 10}}
query={graphql`
query SearchContainerQuery($search: String!, $count: Int!){
# if we want defaults we need to "prepare" them from here
...Search_users @arguments(search: $search, count: $count)
}
`}
environment={this.props.auth.environment}
render={({ error, props: relayProps }) => {
// I use relayProps to avoid possible naming conflicts
if (error) {
console.log(error);
}
if (relayProps) {
// the users props is "masked" from the root that's why we pass it as is
return <Search users={relayProps} />;
}
return <div>No Dice</div>;
}}
/>
And the refetchContainer would look something like:
export default createRefetchContainer(
Search,
{
users: graphql`
# In my schema the root is called RootQueryType
fragment Search_users on RootQueryType
@argumentDefinitions(
search: {type: "String"}
count: {type: "Int!"}
) {
searchUsers(search: $search, first: $count) {
nodes {
id
displayName
username
}
}
}
`
},
graphql`
query SearchRefetchQuery($search: String!, $count: Int!) {
...Search_users @arguments(search: $search, count: $count)
}
`
);
Notice that the above example assumes Relay v1.3 where graphql.experimental
is deprecated. Also, I don't remember if with the @arguments
trick it's possible to make your approach of aliasing the searchUsers
work.
My last suggestion is turning your debugger on and see whats going on when you get the data.
Finally, as per your ments, I agree this might be a BUG. Let's see how things evolve in the issue you reported.
本文标签: javascriptRelay Modern RefetchContainer props aren39t passed to componentStack Overflow
版权声明:本文标题:javascript - Relay Modern RefetchContainer props aren't passed to component - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741325472a2372452.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论