Skip to content
This repository was archived by the owner on Sep 27, 2023. It is now read-only.

Commit 5603868

Browse files
committed
migrate example-hooks to react-relay@experimental
1 parent 50eb2ba commit 5603868

File tree

10 files changed

+395
-384
lines changed

10 files changed

+395
-384
lines changed

.DS_Store

6 KB
Binary file not shown.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import * as React from "react"
2+
3+
interface Props {
4+
fallback: (error: Error) => JSX.Element
5+
}
6+
7+
class ErrorBoundaryWithRetry extends React.Component<Props> {
8+
state = { error: null }
9+
10+
static getDerivedStateFromError(error) {
11+
return { error: error }
12+
}
13+
14+
_retry = () => {
15+
this.setState({ error: null })
16+
}
17+
18+
render() {
19+
const { children, fallback } = this.props
20+
const { error } = this.state
21+
22+
if (error) {
23+
if (typeof fallback === "function") {
24+
return fallback(error, this._retry)
25+
}
26+
return fallback
27+
}
28+
return children
29+
}
30+
}
31+
32+
export default ErrorBoundaryWithRetry

example-hooks/ts/__relay_artifacts__/appQuery.graphql.ts renamed to example-hooks/ts/__relay_artifacts__/TodoRootQuery.graphql.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@
22

33
import { ConcreteRequest } from "relay-runtime";
44
import { FragmentRefs } from "relay-runtime";
5-
export type appQueryVariables = {};
6-
export type appQueryResponse = {
5+
export type TodoRootQueryVariables = {};
6+
export type TodoRootQueryResponse = {
77
readonly viewer: {
88
readonly " $fragmentRefs": FragmentRefs<"TodoApp_viewer">;
99
} | null;
1010
};
11-
export type appQuery = {
12-
readonly response: appQueryResponse;
13-
readonly variables: appQueryVariables;
11+
export type TodoRootQuery = {
12+
readonly response: TodoRootQueryResponse;
13+
readonly variables: TodoRootQueryVariables;
1414
};
1515

1616

1717

1818
/*
19-
query appQuery {
19+
query TodoRootQuery {
2020
viewer {
2121
...TodoApp_viewer
2222
id
@@ -106,7 +106,7 @@ return {
106106
"kind": "Request",
107107
"fragment": {
108108
"kind": "Fragment",
109-
"name": "appQuery",
109+
"name": "TodoRootQuery",
110110
"type": "Query",
111111
"metadata": null,
112112
"argumentDefinitions": [],
@@ -131,7 +131,7 @@ return {
131131
},
132132
"operation": {
133133
"kind": "Operation",
134-
"name": "appQuery",
134+
"name": "TodoRootQuery",
135135
"argumentDefinitions": [],
136136
"selections": [
137137
{
@@ -296,12 +296,12 @@ return {
296296
},
297297
"params": {
298298
"operationKind": "query",
299-
"name": "appQuery",
299+
"name": "TodoRootQuery",
300300
"id": null,
301-
"text": "query appQuery {\n viewer {\n ...TodoApp_viewer\n id\n }\n}\n\nfragment TodoApp_viewer on User {\n id\n totalCount\n ...TodoListFooter_viewer\n ...TodoList_viewer\n}\n\nfragment TodoListFooter_viewer on User {\n id\n completedCount\n completedTodos: todos(status: \"completed\", first: 2147483647) {\n edges {\n node {\n id\n complete\n }\n }\n }\n totalCount\n}\n\nfragment TodoList_viewer on User {\n todos(first: 2147483647) {\n edges {\n node {\n id\n complete\n ...Todo_todo\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n id\n totalCount\n completedCount\n ...Todo_viewer\n}\n\nfragment Todo_todo on Todo {\n complete\n id\n text\n}\n\nfragment Todo_viewer on User {\n id\n totalCount\n completedCount\n}\n",
301+
"text": "query TodoRootQuery {\n viewer {\n ...TodoApp_viewer\n id\n }\n}\n\nfragment TodoApp_viewer on User {\n id\n totalCount\n ...TodoListFooter_viewer\n ...TodoList_viewer\n}\n\nfragment TodoListFooter_viewer on User {\n id\n completedCount\n completedTodos: todos(status: \"completed\", first: 2147483647) {\n edges {\n node {\n id\n complete\n }\n }\n }\n totalCount\n}\n\nfragment TodoList_viewer on User {\n todos(first: 2147483647) {\n edges {\n node {\n id\n complete\n ...Todo_todo\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n id\n totalCount\n completedCount\n ...Todo_viewer\n}\n\nfragment Todo_todo on Todo {\n complete\n id\n text\n}\n\nfragment Todo_viewer on User {\n id\n totalCount\n completedCount\n}\n",
302302
"metadata": {}
303303
}
304304
};
305305
})();
306-
(node as any).hash = '14aafc6977e28bcb7c5b2392f3fdae03';
306+
(node as any).hash = '393316ee6f1f0e29c32409006ee007f0';
307307
export default node;

example-hooks/ts/app.tsx

Lines changed: 19 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -10,59 +10,41 @@
1010
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1111
*/
1212

13-
import "todomvc-common";
13+
import "todomvc-common"
1414

15-
import * as React from "react";
16-
import * as ReactDOM from "react-dom";
15+
import * as React from "react"
16+
import * as ReactDOM from "react-dom"
1717

18-
import { QueryRenderer, graphql } from "react-relay";
19-
import { Environment, Network, RecordSource, Store } from "relay-runtime";
18+
import { RelayEnvironmentProvider } from "react-relay"
19+
import { Environment, Network, RecordSource, Store } from "relay-runtime"
2020

21-
import TodoApp from "./components/TodoApp";
22-
import { appQuery } from "./__relay_artifacts__/appQuery.graphql";
21+
import TodoRoot from "./components/TodoRoot"
2322

24-
const mountNode = document.getElementById("root");
23+
const mountNode = document.getElementById("root")
2524

2625
function fetchQuery(operation: any, variables: any) {
2726
return fetch("/graphql", {
2827
method: "POST",
2928
headers: {
30-
"Content-Type": "application/json"
29+
"Content-Type": "application/json",
3130
},
3231
body: JSON.stringify({
3332
query: operation.text,
34-
variables
35-
})
33+
variables,
34+
}),
3635
}).then(response => {
37-
return response.json();
38-
});
36+
return response.json()
37+
})
3938
}
4039

4140
const modernEnvironment = new Environment({
4241
network: Network.create(fetchQuery),
43-
store: new Store(new RecordSource())
44-
});
42+
store: new Store(new RecordSource()),
43+
})
4544

4645
ReactDOM.render(
47-
<QueryRenderer<appQuery>
48-
environment={modernEnvironment}
49-
query={graphql`
50-
query appQuery {
51-
viewer {
52-
...TodoApp_viewer
53-
}
54-
}
55-
`}
56-
variables={{}}
57-
render={({ error, props }) => {
58-
if (props && props.viewer) {
59-
return <TodoApp viewer={props.viewer} />;
60-
} else if (props || error) {
61-
console.error(`Unexpected data: ${props || error}`);
62-
} else {
63-
return <div>Loading</div>;
64-
}
65-
}}
66-
/>,
67-
mountNode
68-
);
46+
<RelayEnvironmentProvider environment={modernEnvironment}>
47+
<TodoRoot />
48+
</RelayEnvironmentProvider>,
49+
mountNode,
50+
)

example-hooks/ts/components/Todo.tsx

Lines changed: 91 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -10,128 +10,110 @@
1010
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1111
*/
1212

13-
import ChangeTodoStatusMutation from '../mutations/ChangeTodoStatusMutation';
14-
import RemoveTodoMutation from '../mutations/RemoveTodoMutation';
15-
import RenameTodoMutation from '../mutations/RenameTodoMutation';
16-
import TodoTextInput from './TodoTextInput';
13+
import ChangeTodoStatusMutation from "../mutations/ChangeTodoStatusMutation"
14+
import RemoveTodoMutation from "../mutations/RemoveTodoMutation"
15+
import RenameTodoMutation from "../mutations/RenameTodoMutation"
16+
import TodoTextInput from "./TodoTextInput"
1717

18-
import * as React from 'react';
19-
import {
20-
createFragmentContainer,
21-
graphql,
22-
RelayProp,
23-
} from 'react-relay';
18+
import * as React from "react"
19+
import { graphql, useRelayEnvironment, useFragment } from "react-relay"
2420

25-
import classnames from 'classnames';
21+
import classnames from "classnames"
2622

27-
import { Todo_todo } from '../__relay_artifacts__/Todo_todo.graphql';
28-
import { Todo_viewer } from '../__relay_artifacts__/Todo_viewer.graphql';
29-
import { ChangeEvent } from 'react';
30-
import { Environment } from 'relay-runtime';
23+
import { Todo_todo$key } from "../__relay_artifacts__/Todo_todo.graphql"
24+
import { Todo_viewer$key } from "../__relay_artifacts__/Todo_viewer.graphql"
25+
import { ChangeEvent } from "react"
3126

3227
interface Props {
33-
relay: RelayProp
34-
todo: Todo_todo
35-
viewer: Todo_viewer
28+
todo: Todo_todo$key
29+
viewer: Todo_viewer$key
3630
}
3731

38-
class Todo extends React.Component<Props> {
39-
state = {
40-
isEditing: false,
41-
};
42-
_handleCompleteChange = (e: ChangeEvent<HTMLInputElement>) => {
43-
const complete = e.target.checked;
44-
ChangeTodoStatusMutation.commit(
45-
(this.props.relay && this.props.relay.environment) as Environment,
46-
complete,
47-
this.props.todo,
48-
this.props.viewer,
49-
);
50-
};
51-
_handleDestroyClick = () => {
52-
this._removeTodo();
53-
};
54-
_handleLabelDoubleClick = () => {
55-
this._setEditMode(true);
56-
};
57-
_handleTextInputCancel = () => {
58-
this._setEditMode(false);
59-
};
60-
_handleTextInputDelete = () => {
61-
this._setEditMode(false);
62-
this._removeTodo();
63-
};
64-
_handleTextInputSave = (text: string) => {
65-
this._setEditMode(false);
66-
RenameTodoMutation.commit(
67-
(this.props.relay && this.props.relay.environment) as Environment,
68-
text,
69-
this.props.todo,
70-
);
71-
};
72-
_removeTodo() {
73-
RemoveTodoMutation.commit(
74-
(this.props.relay && this.props.relay.environment) as Environment,
75-
this.props.todo,
76-
this.props.viewer,
77-
);
32+
const Todo = (props: Props) => {
33+
const [isEditing, setIsEditing] = React.useState(false)
34+
35+
const environment = useRelayEnvironment()
36+
37+
const todo = useFragment(
38+
graphql`
39+
fragment Todo_todo on Todo {
40+
complete
41+
id
42+
text
43+
}
44+
`,
45+
props.todo,
46+
)
47+
48+
const viewer = useFragment(
49+
graphql`
50+
fragment Todo_viewer on User {
51+
id
52+
totalCount
53+
completedCount
54+
}
55+
`,
56+
props.viewer,
57+
)
58+
59+
const handleCompleteChange = (e: ChangeEvent<HTMLInputElement>) => {
60+
const complete = e.target.checked
61+
ChangeTodoStatusMutation.commit(environment, complete, todo!, viewer!)
62+
}
63+
const handleDestroyClick = () => {
64+
removeTodo()
65+
}
66+
const handleLabelDoubleClick = () => {
67+
setIsEditing(true)
68+
}
69+
const handleTextInputCancel = () => {
70+
setIsEditing(false)
7871
}
79-
_setEditMode = (shouldEdit: boolean) => {
80-
this.setState({isEditing: shouldEdit});
81-
};
82-
renderTextInput() {
72+
const handleTextInputDelete = () => {
73+
setIsEditing(false)
74+
removeTodo()
75+
}
76+
const handleTextInputSave = (text: string) => {
77+
setIsEditing(false)
78+
RenameTodoMutation.commit(environment, text, todo!)
79+
}
80+
function removeTodo() {
81+
RemoveTodoMutation.commit(environment, todo!, viewer!)
82+
}
83+
84+
function renderTextInput() {
8385
return (
8486
<TodoTextInput
8587
className="edit"
8688
commitOnBlur={true}
87-
initialValue={this.props.todo.text}
88-
onCancel={this._handleTextInputCancel}
89-
onDelete={this._handleTextInputDelete}
90-
onSave={this._handleTextInputSave}
89+
initialValue={todo!.text}
90+
onCancel={handleTextInputCancel}
91+
onDelete={handleTextInputDelete}
92+
onSave={handleTextInputSave}
9193
/>
92-
);
93-
}
94-
render() {
95-
return (
96-
<li
97-
className={classnames({
98-
completed: this.props.todo.complete,
99-
editing: this.state.isEditing,
100-
})}>
101-
<div className="view">
102-
<input
103-
checked={!!this.props.todo.complete}
104-
className="toggle"
105-
onChange={this._handleCompleteChange}
106-
type="checkbox"
107-
/>
108-
<label onDoubleClick={this._handleLabelDoubleClick}>
109-
{this.props.todo.text}
110-
</label>
111-
<button
112-
className="destroy"
113-
onClick={this._handleDestroyClick}
114-
/>
115-
</div>
116-
{this.state.isEditing && this.renderTextInput()}
117-
</li>
118-
);
94+
)
11995
}
96+
97+
return (
98+
<li
99+
className={classnames({
100+
completed: todo!.complete,
101+
editing: isEditing,
102+
})}
103+
>
104+
<div className="view">
105+
<input
106+
checked={!!todo!.complete}
107+
className="toggle"
108+
onChange={handleCompleteChange}
109+
type="checkbox"
110+
/>
111+
<label onDoubleClick={handleLabelDoubleClick}>{todo!.text}</label>
112+
<button className="destroy" onClick={handleDestroyClick} />
113+
</div>
114+
{isEditing && renderTextInput()}
115+
</li>
116+
)
120117
}
121118

122-
export default createFragmentContainer(Todo, {
123-
todo: graphql`
124-
fragment Todo_todo on Todo {
125-
complete,
126-
id,
127-
text,
128-
}
129-
`,
130-
viewer: graphql`
131-
fragment Todo_viewer on User {
132-
id,
133-
totalCount,
134-
completedCount,
135-
}
136-
`,
137-
});
119+
export default Todo

0 commit comments

Comments
 (0)