Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 0722246

Browse files
update exercise Context
1 parent 56346c4 commit 0722246

File tree

3 files changed

+93
-12
lines changed

3 files changed

+93
-12
lines changed

‎src/components/patterns/Context/Page.jsx‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,22 @@ const Page = () => (
2222
<Example />
2323
<hr />
2424
<Exercise />
25+
<h3>Bonus Exercise</h3>
26+
<p>
27+
<input type="checkbox" />
28+
b.1. In{" "}
29+
<code>
30+
src/components/patterns/Context/exercise/GraphQLProvider.jsx
31+
</code>{" "}
32+
we are using <code>const memoizedHashGql = memoize(hashGql);</code>.
33+
Should we use useMemo instead? Why?
34+
</p>
35+
<p>
36+
<input type="checkbox" />
37+
b.2. In our current implementation, although there is a cache (data key in
38+
our reducer) for each pair query & variables, we can only send 1 query at
39+
a time. How would you make it possible to send requests concurrently?
40+
</p>
2541
</React.Fragment>
2642
);
2743

‎src/components/patterns/Context/exercise/GraphQLProvider.jsx‎

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import React, { useReducer, useContext, useEffect } from "react";
2-
import { memoize, hashGql } from "./utils";
2+
import { memoize, hashGql,createClient } from "./utils";
33

44
const RECEIVE_DATA = "RECEIVE_DATA";
55
const SET_ERROR = "SET_ERROR";
66

77
export const StoreContext = React.createContext();
8-
exportconstClientContext=React.createContext();
8+
// 🚧 1.1 Create a context for the data fetching client
99

1010
const reducer = (state, action) => {
1111
switch (action.type) {
@@ -25,7 +25,6 @@ const reducer = (state, action) => {
2525

2626
export const GraphQLProvider = ({
2727
children,
28-
client,
2928
initialState = {
3029
data: {},
3130
error: null,
@@ -34,20 +33,21 @@ export const GraphQLProvider = ({
3433
}) => {
3534
const [state, dispatch] = useReducer(reducer, initialState);
3635

36+
// 🚧 Part 1.2. Add your ClientProvider inside the return
3737
return (
38-
<ClientContext.Provider value={{ client }}>
39-
<StoreContext.Provider value={[state, dispatch]}>
40-
{children}
41-
</StoreContext.Provider>
42-
</ClientContext.Provider>
38+
<StoreContext.Provider value={[state, dispatch]}>
39+
{children}
40+
</StoreContext.Provider>
4341
);
4442
};
4543

46-
// 🚧 Should we use useMemo for this memoized function? Why?
44+
// 🚧 Bonus exercise, should we use useMemo for this memoized function? Why?
4745
const memoizedHashGql = memoize(hashGql);
4846

4947
export const useQuery = (query, { variables }) => {
50-
const { client } = useClient();
48+
// 🚧 1.3. Use the client from the context, instead of this hardcoded implementation. You can create a handy useClient custom hook (almost implemented at the end of the file).
49+
// Why moving the client to the context? For testing. E.g. https://www.apollographql.com/docs/react/development-testing/testing/#mockedprovider
50+
const client = createClient({ url: "https://rickandmortyapi.com/graphql/" });
5151
const [state, dispatch] = useContext(StoreContext);
5252
const { loading, error, data: cache } = state;
5353
const cacheKey = memoizedHashGql(query, variables);
@@ -72,13 +72,13 @@ export const useQuery = (query, { variables }) => {
7272
error,
7373
})
7474
);
75-
}, [query, cacheKey, variables, dispatch, data]);// do I need dispatch here if it comes from useReducer?
75+
}, [query, cacheKey, variables, dispatch, data]);
7676

7777
return { data, loading, error };
7878
};
7979

8080
export const useClient = () => {
81-
const {client }=useContext(ClientContext)||{};
81+
const client =null;// 🚧 get the client from the context here
8282
if (!client) {
8383
throw new Error(
8484
"No GraphQL client found, please make sure that you are providing a client prop to the GraphQL Provider"

‎src/components/patterns/Context/exercise/index.jsx‎

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,71 @@ const Root = () => {
2626
cases, along with custom hooks and some other React additional Hooks
2727
</h4>
2828
<img src={data.character.image} alt={data.character.name} />
29+
<h4>Exercise part 1, using context for the GraphQL client</h4>
30+
<p>
31+
Our current implementation works, but we won't be able to easly write
32+
tests for our GraphQL queries because the fetching to the API is
33+
hardcoded.
34+
</p>
35+
<p>
36+
We can solve that by moving the GraphQL data fetching to the context.
37+
This way we can "inject" the data fetching dependency via context. Just
38+
like the{" "}
39+
<a
40+
href="https://www.apollographql.com/docs/react/development-testing/testing/#mockedprovider"
41+
target="_blank"
42+
rel="noopener noreferrer"
43+
>
44+
MockedProvider
45+
</a>{" "}
46+
from Apollo
47+
</p>
48+
<h4>Tasks part 1:</h4>
49+
<p>
50+
<input type="checkbox" /> 1.1. Go to{" "}
51+
<code>
52+
src/components/patterns/Context/exercise/GraphQLProvider.jsx
53+
</code>{" "}
54+
and create a context for the data fetching client. You can call it
55+
ClientContext.
56+
</p>
57+
<p>
58+
<input type="checkbox" /> 1.2. Add the ClientContext Provider to the
59+
GraphQLProvider. Should the ClientContext wrap StoreContext? The other
60+
way around? Does it matter in this case?
61+
</p>
62+
<p>
63+
<input type="checkbox" /> 1.3. Use the client from the context inside
64+
your useQuery. You can create a handy useClient custom hook like we did
65+
in the example{" "}
66+
<code>
67+
src/components/patterns/Context/example/modal.jsx -> useModal function{" "}
68+
</code>
69+
</p>
70+
71+
<h4>Tasks part 2:</h4>
72+
<blockquote>
73+
In large component trees, an alternative we recommend is to pass down a
74+
dispatch function from useReducer via context...
75+
<br />
76+
<br />
77+
...If you use context to pass down the state too,{" "}
78+
<strong>use two different context types</strong> — the dispatch context
79+
never changes, so components that read it don’t need to rerender unless
80+
they also need the application state.{" "}
81+
<a
82+
href="https://reactjs.org/docs/hooks-faq.html#how-to-avoid-passing-callbacks-down"
83+
target="_blank"
84+
rel="noopener noreferrer"
85+
>
86+
<strong> React docs</strong>
87+
</a>
88+
</blockquote>
89+
<p>🤔 React docs say "use two different context types". Let's do it!</p>
90+
<p>
91+
Task: create two different context types for our StoreContext. One
92+
context for the dispatch, and another context for the state.
93+
</p>
2994
</div>
3095
);
3196
};

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /