Get Start
1. Setup
npm install @apollo/client graphql
2. Initialize ApolloClient
import {
ApolloClient,
InMemoryCache,
ApolloProvider,
useQuery,
gql
} from "@apollo/client";
const client = new ApolloClient({
uri: 'https://48p1r2roz4.sse.codesandbox.io',
cache: new InMemoryCache()
});
- uri: graphql server 地址
- cache: is an instance of
InMemoryCache
, which Apollo Client uses to cache query results after fetching them.
// const client = ...
client
.query({
query: gql`
query GetRates {
rates(currency: "USD") {
currency
}
}
`
})
.then(result => console.log(result));
3. Connect your client to React
import React from 'react';
import { render } from 'react-dom';
import {
ApolloClient,
InMemoryCache,
ApolloProvider,
useQuery,
gql
} from "@apollo/client";
const client = new ApolloClient({
uri: 'https://48p1r2roz4.sse.codesandbox.io',
cache: new InMemoryCache()
});
function App() {
return (
<div>
<h2>My first Apollo app 🚀</h2>
</div>
);
}
render(
<ApolloProvider client={client}> <App /> </ApolloProvider>, document.getElementById('root'),
);
4. Fetch data with useQuery
const EXCHANGE_RATES = gql`
query GetExchangeRates {
rates(currency: "USD") {
currency
rate
}
}
`;
function ExchangeRates() {
const { loading, error, data } = useQuery(EXCHANGE_RATES);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return data.rates.map(({ currency, rate }) => (
<div key={currency}>
<p>
{currency}: {rate}
</p>
</div>
));
}
Whenever this component renders, the useQuery
hook automatically executes our query and returns a result object containing loading
, error
, and data
properties
Updating cached query results
Apollo 会对查询结果自动做缓存。因此Apollo提供了 缓存策略Polling和refetching。
Polling
轮询通过在指定的间隔定期执行查询,提供与服务器的近实时同步。要对查询启用轮询,请向useQuery钩子传递一个pollInterval配置选项,间隔时间为毫秒:
function DogPhoto({ breed }) {
const { loading, error, data } = useQuery(GET_DOG_PHOTO, {
variables: { breed },
pollInterval: 500,
});
if (loading) return null;
if (error) return `Error! ${error}`;
return (
<img src={data.dog.displayImage} style={{ height: 100, width: 100 }} />
);
}
通过将pollInterval设置为500,我们每0.5秒从服务器获取当前品种的映像。注意,如果将pollInterval设置为0,则查询不会轮询。
Refetching
function DogPhoto({ breed }) {
const { loading, error, data, refetch } = useQuery(GET_DOG_PHOTO, { variables: { breed }
});
if (loading) return null;
if (error) return `Error! ${error}`;
return (
<div>
<img src={data.dog.displayImage} style={{ height: 100, width: 100 }} />
<button onClick={() => refetch()}>Refetch!</button> </div>
);
}
<button onClick={() => refetch({
breed: 'dalmatian' // Always refetches a dalmatian instead of original breed
})}>Refetch!</button>
import { NetworkStatus } from '@apollo/client';
function DogPhoto({ breed }) {
const { loading, error, data, refetch, networkStatus } = useQuery(
GET_DOG_PHOTO,
{
variables: { breed },
notifyOnNetworkStatusChange: true,
},
);
if (networkStatus === NetworkStatus.refetch) return 'Refetching!';
if (loading) return null;
if (error) return `Error! ${error}`;
return (
<div>
<img src={data.dog.displayImage} style={{ height: 100, width: 100 }} />
<button onClick={() => refetch()}>Refetch!</button>
</div>
);
}
notifyOnNetworkStatusChange: true
notifyOnNetworkStatusChange: true 表示执行refetch方法,同时更新loading状态
缓存策略
const { loading, error, data } = useQuery(GET_DOGS, {
fetchPolicy: "network-only", // Used for first execution
nextFetchPolicy: "cache-first" // Used for subsequent executions});
如果指定了nextFetchPolicy则fetchPolicy被用于第一次缓存
阿波罗客户端首先对缓存执行查询。如果所有请求的数据都在缓存中,则返回该数据。否则,Apollo Client将对GraphQL服务器执行查询,并在缓存数据后返回该数据。 优先级最小化应用程序发送的网络请求的数量。 这是默认的获取策略。 | |
Apollo Client仅针对缓存执行查询。在这种情况下,它不会查询你的服务器。 如果缓存不包含所有请求字段的数据,仅缓存查询将抛出错误。 | |
Apollo Client对缓存和GraphQL服务器执行完整查询。如果服务器端查询的结果修改了缓存字段,查询将自动更新。 提供快速响应,同时帮助保持缓存数据与服务器数据一致 | |
阿波罗客户端对GraphQL服务器执行完整查询,而不首先检查缓存。查询结果存储在缓存中。 优先级与服务器数据保持一致,但不能在缓存数据可用时提供近乎即时的响应。 | |
类似于仅限网络,除了查询的结果不存储在缓存中。 | |
使用与缓存优先相同的逻辑,只是当底层字段值更改时,此查询不会自动更新。您仍然可以使用refetch和updateQueries手动更新这个查询。 |
Mutation
执行更新服务器数据的操作。更新操作结果有俩种方式,重新请求、直接更新缓存数据。
import { gql, useMutation } from '@apollo/client';
const ADD_TODO = gql`
mutation AddTodo($text: String!) {
addTodo(text: $text) {
id
text
}
}
`;
function AddTodo() {
let input;
const [addTodo, { data, loading, error }] = useMutation(ADD_TODO);
if (loading) return 'Submitting...';
if (error) return `Submission error! ${error.message}`;
return (
<div>
<form
onSubmit={e => {
e.preventDefault();
addTodo({ variables: { text: input.value } });
input.value = '';
}}
>
<input
ref={node => {
input = node;
}}
/>
<button type="submit">Add Todo</button>
</form>
</div>
);
}
给变量提供默认值
const [addTodo, { data, loading, error }] = useMutation(ADD_TODO, {
variables: {
text: "placeholder",
someOtherVariable: 1234,
},
});
Refetching queries
当插入数据执行完成后重新获取数据。查询入参使用最近一次参数。
// Refetches two queries after mutation completes
const [addTodo, { data, loading, error }] = useMutation(ADD_TODO, {
refetchQueries: [
GET_POST, // DocumentNode object parsed with gql
'GetComments' // Query name
],
});
- 参数一:A
DocumentNode
object parsed with thegql
function - 参数二:执行查询的名字
Updating the cache directly
{
"__typename": "Todo",
"id": "5",
"text": "Buy grapes 🍇"
}
Apollo 会根据__typename更新缓存,新缓存的对象不会自动添加到应该包含该字段的列表中。需要添加更新函数。
const GET_TODOS = gql`
query GetTodos {
todos {
id
}
}
`;
function AddTodo() {
let input;
const [addTodo] = useMutation(ADD_TODO, {
update(cache, { data: { addTodo } }) {
cache.modify({
fields: {
todos(existingTodos = []) {
const newTodoRef = cache.writeFragment({
data: addTodo,
fragment: gql`
fragment NewTodo on Todo {
id
type
}
`
});
return [...existingTodos, newTodoRef];
}
}
});
}
});
}
更改缓存可以立即更新视图结果,但是可能人为造成更新缓存结果不正确。可以更新缓存➕网络请求双重检测。
addTodo({
variables: { type: input.value },
update(cache, result) {
// Update the cache as an approximation of server-side mutation effects
},
onQueryUpdated(observableQuery) {
// Define any custom logic for determining whether to refetch
if (shouldRefetchQuery(observableQuery)) {
return observableQuery.refetch();
}
},
})
在onQueryUpdated中编写逻辑是否重新网络请求。如果网络请求数据和缓存数据不同,Apollo会自动更新缓存和视图。
未完待续。。。