Merge pull request #23460 from alloy/relay-better-relay-provided-props-2

[Relay] Various improvements
This commit is contained in:
Eloy Durán
2018-02-06 11:29:19 -05:00
committed by GitHub
9 changed files with 372 additions and 332 deletions

View File

@@ -117,7 +117,7 @@ export class DefaultNetworkLayer implements RelayNetworkLayer {
}
export function createContainer<T>(
component: React.ComponentClass<T> | React.StatelessComponent<T>,
component: React.ComponentType<T>,
params?: CreateContainerOpts
): RelayContainerClass<T>;
export function injectNetworkLayer(networkLayer: RelayNetworkLayer): any;

View File

@@ -1,21 +1,16 @@
export {
QueryRenderer,
fetchQuery,
graphql,
} from "./index";
export { QueryRenderer, fetchQuery, graphql } from "./index";
import {
ConnectionConfig,
RelayPaginationProp as RelayModernPaginationProp,
RelayRefetchProp as RelayModernRefetchProp
RelayRefetchProp as RelayModernRefetchProp,
} from "./index";
export { ConcreteFragment, ConcreteRequest, ConcreteBatchRequest } from "relay-runtime";
import * as RelayRuntimeTypes from "relay-runtime";
import { RelayEnvironmentInterface } from "./classic";
// ~~~~~~~~~~~~~~~~~~~~~
// Maybe Fix
// ~~~~~~~~~~~~~~~~~~~~~
export type ConcreteFragment = any;
export type ConcreteBatch = any;
export type ConcreteFragmentDefinition = object;
export type ConcreteOperationDefinition = object;
@@ -30,7 +25,6 @@ export interface StatelessWithFragment<T> extends React.StatelessComponent<T> {
getFragment: typeof getFragment;
}
export type ReactFragmentComponent<T> = ComponentWithFragment<T> | StatelessWithFragment<T>;
export type ReactBaseComponent<T> = React.ComponentClass<T> | React.StatelessComponent<T>;
export type RelayClassicEnvironment = RelayEnvironmentInterface;
// ~~~~~~~~~~~~~~~~~~~~~
@@ -68,18 +62,18 @@ export interface GeneratedNodeMap {
}
export function createFragmentContainer<T>(
Component: ReactBaseComponent<T>,
Component: React.ComponentType<T>,
fragmentSpec: RelayRuntimeTypes.GraphQLTaggedNode | GeneratedNodeMap
): ReactFragmentComponent<T>;
export function createRefetchContainer<T>(
Component: ReactBaseComponent<T>,
Component: React.ComponentType<T>,
fragmentSpec: RelayRuntimeTypes.GraphQLTaggedNode | GeneratedNodeMap,
taggedNode: RelayRuntimeTypes.GraphQLTaggedNode
): ReactFragmentComponent<T>;
export function createPaginationContainer<T>(
Component: ReactBaseComponent<T>,
Component: React.ComponentType<T>,
fragmentSpec: RelayRuntimeTypes.GraphQLTaggedNode | GeneratedNodeMap,
connectionConfig: ConnectionConfig<T>
): ReactFragmentComponent<T>;

View File

@@ -11,20 +11,36 @@ export {
commitLocalUpdate,
commitRelayModernMutation as commitMutation,
fetchRelayModernQuery as fetchQuery,
GraphQLTaggedNode,
requestRelaySubscription as requestSubscription,
} from "relay-runtime";
import * as React from "react";
import * as RelayRuntimeTypes from "relay-runtime";
// ~~~~~~~~~~~~~~~~~~~~~
// Utility types
// ~~~~~~~~~~~~~~~~~~~~~
// Taken from https://github.com/pelotom/type-zoo
// tslint:disable-next-line:strict-export-declare-modifiers
type Diff<T extends string, U extends string> = ({ [P in T]: P } & { [P in U]: never } & { [x: string]: never })[T];
// tslint:disable-next-line:strict-export-declare-modifiers
type Omit<T, K extends keyof T> = Pick<T, Diff<keyof T, K>>;
export type RemoveRelayProp<P> = Omit<P & { relay: never }, "relay">;
export interface ComponentRef {
componentRef?: (ref: any) => void;
}
export type RelayContainer<T> = React.ComponentType<RemoveRelayProp<T> & ComponentRef>;
// ~~~~~~~~~~~~~~~~~~~~~
// Maybe Fix
// ~~~~~~~~~~~~~~~~~~~~~
export type ConcreteFragment = any;
export type ConcreteBatch = any;
export type ConcreteFragmentDefinition = object;
export type ConcreteOperationDefinition = object;
export type ReactBaseComponent<T> = React.ComponentClass<T> | React.StatelessComponent<T>;
// ~~~~~~~~~~~~~~~~~~~~~
// RelayProp
@@ -40,24 +56,19 @@ export interface RelayProp {
export function RelayQL(strings: string[], ...substitutions: any[]): RelayRuntimeTypes.RelayConcreteNode;
// ~~~~~~~~~~~~~~~~~~~~~
// RelayModernGraphQLTag
// ReactRelayTypes
// ~~~~~~~~~~~~~~~~~~~~~
export interface GeneratedNodeMap {
[key: string]: GraphQLTaggedNode;
[key: string]: RelayRuntimeTypes.GraphQLTaggedNode;
}
export type GraphQLTaggedNode =
| (() => ConcreteFragment | ConcreteBatch)
| {
modern(): ConcreteFragment | ConcreteBatch;
classic(relayQL: typeof RelayQL): ConcreteFragmentDefinition | ConcreteOperationDefinition;
};
/**
* Runtime function to correspond to the `graphql` tagged template function.
* All calls to this function should be transformed by the plugin.
*/
export interface GraphqlInterface {
(strings: string[] | TemplateStringsArray): GraphQLTaggedNode;
experimental(strings: string[] | TemplateStringsArray): GraphQLTaggedNode;
(strings: string[] | TemplateStringsArray): RelayRuntimeTypes.GraphQLTaggedNode;
experimental(strings: string[] | TemplateStringsArray): RelayRuntimeTypes.GraphQLTaggedNode;
}
export const graphql: GraphqlInterface;
@@ -67,7 +78,7 @@ export const graphql: GraphqlInterface;
export interface QueryRendererProps {
cacheConfig?: RelayRuntimeTypes.CacheConfig;
environment: RelayRuntimeTypes.Environment;
query: GraphQLTaggedNode;
query: RelayRuntimeTypes.GraphQLTaggedNode;
render(readyState: ReadyState): React.ReactElement<any> | undefined | null;
variables: RelayRuntimeTypes.Variables;
rerunParamExperimental?: RelayRuntimeTypes.RerunParam;
@@ -87,9 +98,9 @@ export class QueryRenderer extends ReactRelayQueryRenderer {}
// createFragmentContainer
// ~~~~~~~~~~~~~~~~~~~~~
export function createFragmentContainer<T>(
Component: ReactBaseComponent<T>,
fragmentSpec: GraphQLTaggedNode | GeneratedNodeMap
): ReactBaseComponent<T>;
Component: React.ComponentType<T>,
fragmentSpec: RelayRuntimeTypes.GraphQLTaggedNode | GeneratedNodeMap
): RelayContainer<T>;
// ~~~~~~~~~~~~~~~~~~~~~
// createPaginationContainer
@@ -131,16 +142,16 @@ export interface ConnectionConfig<T> {
paginationInfo: { count: number; cursor?: string },
fragmentVariables: RelayRuntimeTypes.Variables
): RelayRuntimeTypes.Variables;
query: GraphQLTaggedNode;
query: RelayRuntimeTypes.GraphQLTaggedNode;
}
export function createPaginationContainer<T>(
Component: ReactBaseComponent<T>,
fragmentSpec: GraphQLTaggedNode | GeneratedNodeMap,
Component: React.ComponentType<T>,
fragmentSpec: RelayRuntimeTypes.GraphQLTaggedNode | GeneratedNodeMap,
connectionConfig: ConnectionConfig<T>
): ReactBaseComponent<T>;
): RelayContainer<T>;
// ~~~~~~~~~~~~~~~~~~~~~
// createFragmentContainer
// createRefetchContainer
// ~~~~~~~~~~~~~~~~~~~~~
export interface RefetchOptions {
force?: boolean;
@@ -157,7 +168,7 @@ export type RelayRefetchProp = RelayProp & {
): RelayRuntimeTypes.Disposable;
};
export function createRefetchContainer<T>(
Component: ReactBaseComponent<T>,
fragmentSpec: GraphQLTaggedNode | GeneratedNodeMap,
taggedNode: GraphQLTaggedNode
): ReactBaseComponent<T>;
Component: React.ComponentType<T>,
fragmentSpec: RelayRuntimeTypes.GraphQLTaggedNode | GeneratedNodeMap,
taggedNode: RelayRuntimeTypes.GraphQLTaggedNode
): RelayContainer<T>;

View File

@@ -1,15 +1,14 @@
import * as React from "react";
import * as Relay from "react-relay/classic";
import { CompatContainer } from "./react-relay-compat-tests";
interface Props {
text: string;
userId: string;
}
// tslint:disable-next-line no-empty-interface
interface Response {}
export default class AddTweetMutation extends Relay.Mutation<Props, Response> {
export default class AddTweetMutation extends Relay.Mutation<Props, {}> {
getMutation() {
return Relay.QL`mutation{addTweet}`;
}
@@ -64,6 +63,7 @@ const ArtworkContainer = Relay.createContainer(Artwork, {
artwork: () => Relay.QL`
fragment on Artwork {
title
${CompatContainer.getFragment("whatever")}
}
`,
},
@@ -83,7 +83,7 @@ class StubbedArtwork extends React.Component {
setVariables: () => {},
forceFetch: () => {},
hasOptimisticUpdate: () => false,
getPendingTransactions: (): Relay.RelayMutationTransaction[] => [],
getPendingTransactions: (): any => undefined,
commitUpdate: () => {},
},
};

View File

@@ -0,0 +1,53 @@
import * as React from "react";
import {
QueryRenderer as CompatQueryRenderer,
createFragmentContainer as createFragmentContainerCompat,
commitMutation as commitMutationCompat,
CompatEnvironment,
RelayPaginationProp as RelayPaginationPropCompat,
} from "react-relay/compat";
import { configs, mutation, optimisticResponse } from "./react-relay-tests";
// testting compat mutation with classic environment
function markNotificationAsReadCompat(environment: CompatEnvironment, source: string, storyID: string) {
const variables = {
input: {
source,
storyID,
},
};
commitMutationCompat(environment, {
configs,
mutation,
optimisticResponse,
variables,
onCompleted: (response, errors) => {
console.log("Response received from server.");
},
onError: err => console.error(err),
updater: (store, data) => {
const field = store.get(storyID);
if (field) {
field.setValue(data.story, "story");
}
}
});
}
interface CompatProps {
relay: RelayPaginationPropCompat;
}
class CompatComponent extends React.Component<CompatProps> {
markNotificationAsRead(source: string, storyID: string) {
markNotificationAsReadCompat(this.props.relay.environment, source, storyID);
}
render() {
return (<div/>);
}
}
export const CompatContainer = createFragmentContainerCompat(CompatComponent, {});

View File

@@ -1,9 +1,6 @@
import * as React from "react";
import { Environment, Network, RecordSource, Store, ConnectionHandler } from "relay-runtime";
import { Environment, Network, RecordSource, Store, ConnectionHandler, FragmentReference } from "relay-runtime";
////////////////////////////
// RELAY MODERN TESTS
///////////////////////////
import {
graphql,
commitMutation,
@@ -13,7 +10,8 @@ import {
requestSubscription,
QueryRenderer,
RelayRefetchProp,
RelayPaginationProp
RelayPaginationProp,
RelayProp
} from "react-relay";
// ~~~~~~~~~~~~~~~~~~~~~
@@ -54,63 +52,137 @@ const MyQueryRenderer = (props: { name: string }) => (
/>
);
// ~~~~~~~~~~~~~~~~~~~~~
// Modern FragmentContainer
// ~~~~~~~~~~~~~~~~~~~~~
const MyFragmentContainer = createFragmentContainer(
class TodoListView extends React.Component {
render() {
return <div />;
}
},
{
item: graphql`
fragment TodoItem_item on Todo {
text
isComplete
}
`,
}
);
// ~~~~~~~~~~~~~~~~~~~~~
// Modern RefetchContainer
// ~~~~~~~~~~~~~~~~~~~~~
interface StoryInterface {
id: string;
}
interface FeedStoriesProps {
relay: RelayRefetchProp;
feed: {
stories: { edges: Array<{ node: StoryInterface }> };
};
}
class Story extends React.Component<{ story: StoryInterface }> {}
class FeedStories extends React.Component<FeedStoriesProps> {
render() {
return (
<div>
{this.props.feed.stories.edges.map(edge => <Story story={edge.node} key={edge.node.id} />)}
<button onClick={() => this._loadMore} title="Load More" />
</div>
);
type StoryLike = (storyID: string) => void;
// Artifact produced by relay-compiler-language-typescript
// tslint:disable-next-line:no-const-enum
const enum _Story_story$ref {}
type Story_story$ref = _Story_story$ref & FragmentReference;
// tslint:disable-next-line:interface-over-type-literal
type Story_story = {
readonly id: string;
readonly text: string;
readonly isPublished: boolean;
readonly " $refType": Story_story$ref;
};
const Story = (() => {
interface Props {
relay: RelayRefetchProp;
story: Story_story;
onLike: StoryLike;
ignoreMe?: {};
}
_loadMore() {
// Increments the number of stories being rendered by 10.
const refetchVariables = (fragmentVariables: { count: number }) => ({
count: fragmentVariables.count + 10,
interface State {
isLoading: boolean;
}
class Story extends React.Component<Props> {
state = {
isLoading: false
};
componentDidMount() {
setInterval(this.handleRefresh.bind(this), 1000);
}
handleRefresh() {
this.setState({ isLoading: true });
this.props.relay.refetch({ id: this.props.story.id }, {}, error => {
this.setState({ isLoading: false });
}, { force: true });
}
render() {
return (
<div>
{this.props.story.isPublished ? "" : "Draft: "}
{this.props.story.text}
{this.state.isLoading && <span></span>}
<button onClick={() => this.props.onLike(this.props.story.id)}>LIKE</button>
</div>
);
}
}
const StoryRefetchContainer = createRefetchContainer(
Story,
{
story: graphql`
fragment Story_story on Todo {
id
text
isPublished
}
`,
},
graphql.experimental`
query StoryRefetchQuery($id: ID!) {
story(id: $id) {
...Story_story
}
}
`
);
function doesNotRequireRelayPropToBeProvided() {
const onLike = (id: string) => console.log(`Liked story #${id}`);
const story: { " $fragmentRefs": Story_story$ref } = {} as any;
// TODO: Fix requirement to cast fragment reference as `any`.
<StoryRefetchContainer story={story as any} onLike={onLike} />;
}
return StoryRefetchContainer;
})();
// ~~~~~~~~~~~~~~~~~~~~~
// Modern FragmentContainer
// ~~~~~~~~~~~~~~~~~~~~~
// Artifact produced by relay-compiler-language-typescript
// tslint:disable-next-line:no-const-enum
const enum _FeedStories_feed$ref {}
type FeedStories_feed$ref = _FeedStories_feed$ref & FragmentReference;
// tslint:disable-next-line:interface-over-type-literal
type FeedStories_feed = {
readonly edges: ReadonlyArray<{
readonly node: {
readonly id: string;
readonly " $fragmentRefs": Story_story$ref;
};
}>;
readonly " $refType": FeedStories_feed$ref;
};
const Feed = (() => {
interface Props {
relay: RelayProp;
feed: FeedStories_feed;
onStoryLike: StoryLike;
ignoreMe?: {};
}
const FeedStories: React.SFC<Props> = ({ feed, onStoryLike, relay }) => {
// TODO: Getting env here for no good reason other than needing to test it works.
// If you have a good relavant example, please update!
relay.environment;
const stories = feed.edges.map(edge => {
// TODO: Fix requirement to cast fragment reference as `any`.
return <Story story={edge.node as any} key={edge.node.id} onLike={onStoryLike} />;
});
this.props.relay.refetch(refetchVariables);
}
}
return <div>{stories}</div>;
};
const FeedRefetchContainer = createRefetchContainer(
FeedStories,
{
feed: graphql.experimental`
fragment FeedStories_feed on Feed @argumentDefinitions(count: { type: "Int", defaultValue: 10 }) {
stories(first: $count) {
const FeedFragmentContainer = createFragmentContainer(
FeedStories,
{
feed: graphql`
fragment FeedStories_feed on Feed {
edges {
node {
id
@@ -118,104 +190,137 @@ const FeedRefetchContainer = createRefetchContainer(
}
}
}
}
`,
},
graphql.experimental`
query FeedStoriesRefetchQuery($count: Int) {
feed {
...FeedStories_feed @arguments(count: $count)
}
`,
}
`
);
);
function doesNotRequireRelayPropToBeProvided() {
const onStoryLike = (id: string) => console.log(`Liked story #${id}`);
const feed: { " $fragmentRefs": FeedStories_feed$ref } = {} as any;
// TODO: Fix requirement to cast fragment reference as `any`.
<FeedFragmentContainer feed={feed as any} onStoryLike={onStoryLike} />;
}
return FeedFragmentContainer;
})();
// ~~~~~~~~~~~~~~~~~~~~~
// Modern PaginationContainer
// ~~~~~~~~~~~~~~~~~~~~~
interface FeedProps {
user: { feed: { edges: Array<{ node: StoryInterface }> } };
relay: RelayPaginationProp;
}
class Feed extends React.Component<FeedProps> {
render() {
return (
<div>
{this.props.user.feed.edges.map(edge => <Story story={edge.node} key={edge.node.id} />)}
<button onClick={() => this._loadMore()} title="Load More" />
</div>
);
// Artifact produced by relay-compiler-language-typescript
// tslint:disable-next-line:no-const-enum
const enum _UserFeed_user$ref {}
type UserFeed_user$ref = _UserFeed_user$ref & FragmentReference;
// tslint:disable-next-line:interface-over-type-literal
type UserFeed_user = {
readonly feed: {
readonly pageInfo: {
readonly endCursor?: string | null;
readonly hasNextPage: boolean;
};
readonly " $fragmentRefs": FeedStories_feed$ref;
};
readonly " $refType": UserFeed_user$ref;
};
() => {
interface Props {
relay: RelayPaginationProp;
loadMoreTitle: string;
user: UserFeed_user;
ignoreMe?: {};
}
_loadMore() {
if (!this.props.relay.hasMore() || this.props.relay.isLoading()) {
return;
class UserFeed extends React.Component<Props> {
render() {
const onStoryLike = (id: string) => console.log(`Liked story #${id}`);
// TODO: Fix requirement to cast fragment reference as `any`.
const feed = this.props.user.feed as any;
return (
<div>
<Feed feed={feed} onStoryLike={onStoryLike} />
<button onClick={() => this._loadMore()} title={this.props.loadMoreTitle} />
</div>
);
}
this.props.relay.loadMore(
10, // Fetch the next 10 feed items
e => {
console.log(e);
_loadMore() {
if (!this.props.relay.hasMore() || this.props.relay.isLoading()) {
return;
}
);
}
}
const FeedPaginationContainer = createPaginationContainer(
Feed,
{
user: graphql`
fragment Feed_user on User {
feed(
first: $count
after: $cursor
orderby: $orderBy # other variables
) @connection(key: "Feed_feed") {
edges {
node {
id
...Story_story
this.props.relay.loadMore(
10, // Fetch the next 10 feed items
e => {
console.log(e);
}
);
}
}
const UserFeedPaginationContainer = createPaginationContainer(
UserFeed,
{
user: graphql`
fragment UserFeed_user on User {
feed(
first: $count
after: $cursor
orderby: $orderBy # other variables
) @connection(key: "Feed_feed") {
...FeedStories_feed
pageInfo {
endCursor
hasNextPage
}
}
}
}
`,
},
{
direction: "forward",
getConnectionFromProps(props) {
return props.user && props.user.feed;
`,
},
getFragmentVariables(prevVars, totalCount) {
return {
...prevVars,
count: totalCount,
};
},
getVariables(props, { count, cursor }, fragmentVariables) {
return {
count,
cursor,
// in most cases, for variables other than connection filters like
// `first`, `after`, etc. you may want to use the previous values.
orderBy: fragmentVariables.orderBy,
};
},
query: graphql`
query FeedPaginationQuery($count: Int!, $cursor: String, $orderby: String!) {
user {
# You could reference the fragment defined previously.
...Feed_user
{
direction: "forward",
getConnectionFromProps(props) {
// TODO: Fix requirement to have `edges` and both `pageInfo` details for forward and backward pagination
return props.user && props.user.feed as any;
},
getFragmentVariables(prevVars, totalCount) {
return {
...prevVars,
count: totalCount,
};
},
getVariables(props, { count, cursor }, fragmentVariables) {
return {
count,
cursor,
// in most cases, for variables other than connection filters like
// `first`, `after`, etc. you may want to use the previous values.
orderBy: fragmentVariables.orderBy,
};
},
query: graphql`
query FeedPaginationQuery($count: Int!, $cursor: String, $orderby: String!) {
user {
# You could reference the fragment defined previously.
...Feed_user
}
}
}
`,
`,
}
);
function doesNotRequireRelayPropToBeProvided() {
const user: { " $fragmentRefs": UserFeed_user$ref } = {} as any;
// TODO: Fix requirement to cast fragment reference as `any`.
<UserFeedPaginationContainer loadMoreTitle="Load More" user={user as any} />;
}
);
};
// ~~~~~~~~~~~~~~~~~~~~~
// Modern Mutations
// ~~~~~~~~~~~~~~~~~~~~~
const mutation = graphql`
export const mutation = graphql`
mutation MarkReadNotificationMutation($input: MarkReadNotificationData!) {
markReadNotification(data: $input) {
notification {
@@ -225,7 +330,7 @@ const mutation = graphql`
}
`;
const optimisticResponse = {
export const optimisticResponse = {
markReadNotification: {
notification: {
seenState: "SEEN",
@@ -233,7 +338,7 @@ const optimisticResponse = {
},
};
const configs = [
export const configs = [
{
type: "NODE_DELETE" as "NODE_DELETE",
deletedIDFieldName: "destroyedShipId",
@@ -325,150 +430,3 @@ requestSubscription(
},
}
);
////////////////////////////
// RELAY COMPAT TESTS
///////////////////////////
import {
QueryRenderer as CompatQueryRenderer,
createFragmentContainer as createFragmentContainerCompat,
commitMutation as commitMutationCompat,
CompatEnvironment,
RelayPaginationProp as RelayPaginationPropCompat,
} from "react-relay/compat";
// testting compat mutation with classic environment
function markNotificationAsReadCompat(environment: CompatEnvironment, source: string, storyID: string) {
const variables = {
input: {
source,
storyID,
},
};
commitMutationCompat(environment, {
configs,
mutation,
optimisticResponse,
variables,
onCompleted: (response, errors) => {
console.log("Response received from server.");
},
onError: err => console.error(err),
updater: (store, data) => {
const field = store.get(storyID);
if (field) {
field.setValue(data.story, "story");
}
}
});
}
interface CompatProps {
relay: RelayPaginationPropCompat;
}
export class CompatComponent extends React.Component<CompatProps> {
markNotificationAsRead(source: string, storyID: string) {
markNotificationAsReadCompat(this.props.relay.environment, source, storyID);
}
render() {
return (<div/>);
}
}
const CompatContainer = createFragmentContainerCompat(CompatComponent, {});
////////////////////////////
// RELAY-CLASSIC TESTS
///////////////////////////
import * as Relay from "react-relay/classic";
interface Props {
text: string;
userId: string;
}
export default class AddTweetMutation extends Relay.Mutation<Props, {}> {
getMutation() {
return Relay.QL`mutation{addTweet}`;
}
getFatQuery() {
return Relay.QL`
fragment on AddTweetPayload {
tweetEdge
user
}
`;
}
getConfigs() {
return [
{
type: "RANGE_ADD",
parentName: "user",
parentID: this.props.userId,
connectionName: "tweets",
edgeName: "tweetEdge",
rangeBehaviors: {
"": "append",
},
},
];
}
getVariables() {
return this.props;
}
}
interface ArtwokRelayVariables {
artworkID: string;
}
interface ArtworkProps extends Relay.RelayProps<ArtwokRelayVariables> {
artwork: {
title: string;
};
}
class Artwork extends React.Component<ArtworkProps> {
render() {
return <a href={`/artworks/${this.props.relay.variables.artworkID}`}>{this.props.artwork.title}</a>;
}
}
const ArtworkContainer = Relay.createContainer(Artwork, {
fragments: {
artwork: () => Relay.QL`
fragment on Artwork {
title
${ CompatContainer.getFragment('whatever') }
}
`,
},
});
class StubbedArtwork extends React.Component {
render() {
const props = {
artwork: { title: "CHAMPAGNE FORMICA FLAG" },
relay: {
route: {
name: "champagne",
},
variables: {
artworkID: "champagne-formica-flag",
},
setVariables: () => {},
forceFetch: () => {},
hasOptimisticUpdate: () => false,
getPendingTransactions: (): any => undefined,
commitUpdate: () => {},
},
};
return <ArtworkContainer {...props} />;
}
}

View File

@@ -24,6 +24,7 @@
"classic.d.ts",
"compat.d.ts",
"test/react-relay-tests.tsx",
"test/react-relay-compat-tests.tsx",
"test/react-relay-classic-tests.tsx"
]
}

View File

@@ -17,8 +17,6 @@ export type RelayConcreteNode = any;
export type RelayMutationTransaction = any;
export type RelayMutationRequest = any;
export type RelayQueryRequest = any;
export type ConcreteFragment = any;
export type ConcreteBatch = any;
export type ConcreteFragmentDefinition = object;
export type ConcreteOperationDefinition = object;
@@ -32,6 +30,23 @@ export type ConcreteOperationDefinition = object;
*/
export type RelayContainer = any;
// ~~~~~~~~~~~~~~~~~~~~~
// Used in artifacts
// emitted by
// relay-compiler
// ~~~~~~~~~~~~~~~~~~~~~
// File: https://github.com/facebook/relay/blob/fe0e70f10bbcba1fff89911313ea69f24569464b/packages/relay-runtime/util/RelayConcreteNode.js
export type ConcreteFragment = any;
export type ConcreteRequest = any;
export type ConcreteBatchRequest = any;
export type RequestNode = ConcreteRequest | ConcreteBatchRequest;
// Using `enum` here to create a distinct type and `const` to ensure it doesnt leave any generated code.
// tslint:disable-next-line:no-const-enum
export const enum FragmentReference {}
// ~~~~~~~~~~~~~~~~~~~~~
// RelayQL
// ~~~~~~~~~~~~~~~~~~~~~
@@ -44,9 +59,9 @@ export interface GeneratedNodeMap {
[key: string]: GraphQLTaggedNode;
}
export type GraphQLTaggedNode =
| (() => ConcreteFragment | ConcreteBatch)
| (() => ConcreteFragment | RequestNode)
| {
modern(): ConcreteFragment | ConcreteBatch;
modern(): ConcreteFragment | RequestNode;
classic(relayQL: RelayQL): ConcreteFragmentDefinition | ConcreteOperationDefinition;
};
// ~~~~~~~~~~~~~~~~~~~~~
@@ -85,7 +100,7 @@ export interface PayloadError {
* May return an Observable or Promise of a raw server response.
*/
export function FetchFunction(
operation: ConcreteBatch,
operation: RequestNode,
variables: Variables,
cacheConfig: CacheConfig,
uploadables?: UploadableMap
@@ -99,7 +114,7 @@ export function FetchFunction(
* fourth parameter.
*/
export type SubscribeFunction = (
operation: ConcreteBatch,
operation: RequestNode,
variables: Variables,
cacheConfig: CacheConfig,
observer: LegacyObserver<QueryPayload>

View File

@@ -1,4 +1,12 @@
import { Environment, Network, RecordSource, Store, ConnectionHandler, ViewerHandler, RecordSourceInspector } from "relay-runtime";
import {
Environment,
Network,
RecordSource,
Store,
ConnectionHandler,
ViewerHandler,
RecordSourceInspector,
} from "relay-runtime";
const source = new RecordSource();
const store = new Store(source);