2017-07-21 10 views
9

Ich habe einige Probleme beim Einrichten eines RefetchContainer in Relay Modern. Eine übergeordnete Komponente ist der QueryRenderer, der eine erste Abfrage ausführt und die Requisiten der untergeordneten Komponente entsprechend auffüllt (a-proprietär? Eh? Eh ?!). Der refetchContainer gibt alle unsere Variablen an und führt bei einem onChange-Ereignis des Eingabefelds eine Abfrage mit den neuen Variablen erneut aus. Das alles funktioniert perfekt, außer dass die Requisiten des Kindes nie mit den neuen empfangenen Daten aktualisiert werden. Ich kann den Relay-Speicher aufschlüsseln und feststellen, dass die Abfrage tatsächlich mit den entsprechenden Daten empfangen wurde. Ich habe mir eine Weile den Kopf dagegen gedrückt und würde mich über Hilfe freuen. Vermutlich etwas einfaches, was mir fehlt. Und Gott weiß, Relay Modern Dokumentation ist spärlich.Relay Modern RefetchContainer Requisiten werden nicht an Komponente übergeben

Ich habe herumgestochert und kann keine geeignete Lösung finden. Dieser Kerl scheint ein ähnliches Problem zu haben: relay refetch doesn't show the result

die übergeordnete Komponente mit 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); 

Das Kind Komponente mit 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 sieht wie folgt aus:

# 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] 
} 

Netzwerk c Alles wird passend gemacht und die Daten werden wie erwartet zurückgegeben. NetworkCalls

Es scheint, die @arguments Richtlinie hier aus der erneuten Abruf Abfrage gelassen werden kann:

query SearchRefetchQuery($search: String!) { 
     users: searchUsers(search:$search, first:10){ 
      ...Search_users @arguments(search: $search) 
     } 
} 

(Entfernen sie keine Wirkung zu haben scheinen)

versucht, ich habe das Hinzufügen der @arguments Anweisung an das Fragment der Elternkomponente gemäß der Empfehlung hier: Pass variables to fragment container in relay modern, ohne Wirkung.

+0

leider nicht viel helfen .. FWIW Ich habe die QueryRenderer für einfach vorbei neue Requisiten refetchContainers vollständig fallen gelassen, die die Arbeit erledigt wird. Beispiel: https://github.com/NCI-GDC/portal-ui/blob/next/src/packages/@ncigdc/modern_components/GenesTable/GenesTable.relay.js – azium

+1

@azium Ja, das scheint ganz gut zu funktionieren. Es stört mich nur, dass der eigens dafür entwickelte refetchContainer so schwierig einzurichten ist! – cntrlz

+0

ich genau das gleiche Problem mit und ich bin hämmern TOO meinen Kopf an der Wand :( –

Antwort

3

Oh ich glaube, ich habe ein ähnliches Problem durchgemacht. Wenn ich mich richtig erinnere, glaube ich, dass das "id" Relay die Komponente identifiziert, an die die Requisiten übergeben werden sollen, einschließlich der Variablen für die anfängliche Abfrage, also versuchen Sie, Ihr Containerfragment aus der QueryRenderer-Abfrage auszupacken.

Das Setup, das für mich gearbeitet ist so etwas wie die folgenden:

<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>; 
    }} 
/> 

Und die refetchContainer würde in etwa so aussehen:

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) 
    } 
    ` 
); 

Beachten Sie, dass das obige Beispiel nimmt Relay v1.3 wo graphql.experimental ist veraltet. Auch ich erinnere mich nicht, wenn mit dem @arguments Trick es möglich ist, Ihren Ansatz des Aliasing searchUsers Arbeit zu machen.

Mein letzter Vorschlag ist, Ihren Debugger einzuschalten und zu sehen, was los ist, wenn Sie die Daten bekommen.

Schließlich, nach Ihren Kommentaren, stimme ich zu, dass dies eine BUG sein könnte. Lassen Sie uns sehen, wie sich die Dinge in dem von Ihnen gemeldeten Problem entwickeln.

2

Wie in anderen Antworten erwähnt, ist dies eigentlich erwartet Verhalten, und ich werde versuchen, auf die Antwort ein wenig zu erweitern.

Wenn refetch aufgerufen wird und refetchQuery ausgeführt wird, verwendet Relay das Ergebnis der Abfrage nicht zum erneuten Rendern der Komponente. Es wird lediglich die Payload in den Store normalisiert und alle relevanten Subscriptions ausgelöst. Dies bedeutet, dass, wenn die abgerufenen Daten nicht mit den Daten verknüpft sind, für die der angehängte Container abonniert ist (z. B. unter Verwendung einer völlig anderen Knoten-ID, die keine Datenüberlappungen aufweist), dann wird die Komponente nicht erneut gerendert.

In diesem speziellen Szenario ist der Grund, warum der Container nicht erneut gerendert wird, d. H. Warum die Änderungen von refetchQuery nicht abonniert wurden, aufgrund der Einrichtung von Subskriptionen. Eine Subskription ist im Grunde eine Subskription für eine snapshot, die im Wesentlichen ein konkretes Fragment und die damit verbundenen Daten und Datensätze zu einem bestimmten Zeitpunkt darstellt - wenn sich die mit einer Momentaufnahme verbundenen Datensätze ändern, wird die Subskription für diese Momentaufnahme benachrichtigt Änderungen.

In diesem Fall gegeben, dass das Fragment für den Behälter keine Variablen hat, die Momentaufnahme, die es zeichnen wird nur mit dem Anfangs-Knoten zugeordnet werden; Nach dem erneuten Abrufen und dem Aktualisieren des Speichers werden die Datensätze für den neuen Knoten aktualisiert, aber der Datensatz, der diesem ursprünglichen Snapshot zugeordnet ist, hat sich nicht geändert, sodass der abonnierte Container nicht benachrichtigt wird. Diese

bedeutet, dass erneut abrufen Behälter werden nur wirklich gemeint verwendet werden, wenn Sie Variablen in der Komponente Fragment ändern. Die hier bereitgestellten Lösungen sind gültig, d. H. Enthalten Variablen in dem Fragment für den Refetch-Container oder setzen neue Variablen eine Ebene höher in dem QueryRenderer.

Dies könnte auf jeden Fall in der Dokumentation gemacht klar sein, also werde ich sie, dies zu reflektieren aktualisieren. Ich hoffe das hilft!

Verwandte Themen