跳至主要内容

GraphQL 查询

GraphQL 查询可以使用 graphQLSelector()graphQLSelectorFamily() 完成。(底层支持由 atom effects 提供)。但首先,请确保 设置你的 Relay 环境.

简单 GraphQL 查询

graphQLSelector() 可用于创建一个与 GraphQL 查询 同步的 selector。此 selector 有助于保持 GraphQL 查询和 Recoil 数据流图的同步。它可以依赖于上游 Recoil atom/selector 来确定 变量 用于 GraphQL 查询或转换结果。任何对 Relay GraphQL 状态的 变异局部更新延迟数据实时查询 也会自动与 selector 同步,并导致其更新。这使你能够将服务器视为真理源,而 selector 作为本地缓存。

const userNameQuery = graphQLSelector({
key: 'UserName',
environment: myEnvironmentKey,
query: graphql`
query UserNameQuery($id: ID!) {
user(id: $id) {
name
}
}
`,
variables: ({get}) => ({id: get(currentIDAtom)}),
mapResponse: data => data.user?.name,
});
function MyComponent() {
const seenCount = useRecoilValue(seenCountQuery);
return <span>{seenCount}</span>;
}

除了使用其他上游 atom/selector 来计算 GraphQL 查询变量之外,graphQLSelector() 也可以被其他下游 selector 使用来提供派生状态。

const pictureForUserState = selector({
key: 'PictureForUser',
get: async ({get}) => {
const username = get(userNameQuery);
const picture = await fetch(urlForUserNamePicture(username));
return picture;
},
});

带有参数的 GraphQL 查询

graphQLSelectorFamily() 允许你使用参数,除了其他 Recoil 状态来计算查询变量。参数可以根据组件的 props、React 状态、在另一个 Recoil selector 中使用等等来确定。

const userQuery = graphQLSelectorFamily({
key: 'UserQuery',
environment: myEnvironmentKey,
query: graphql`
query UserQuery($id: ID!, $clientID: ClientID!) {
user(id: $id, client_id: $clientID) {
name
address
}
}
`,
variables: id => ({get}) => ({id, clientID: get(clientIDAtom}),
mapResponse: data => data.user,
});
function MyComponent(props) {
const user = useRecoilValue(userQuery(props.userID));

return (
<div>
<h1>{user.name}</h1>
</div>
);
}

GraphQL 片段

GraphQL 查询还可以通过使用 GraphQL 片段 来包含 @inline 指令和 readInlineData()

const userNameFragment = graphql`
fragment UserNameFragment on User @inline {
name
}
`;
import {readInlineData} from 'relay-runtime';

const userNameQuery = graphQLSelectorFamily({
key: 'UserNameQuery',
environment: myEnvironmentKey,
query: graphql`
query UserNameQuery($id: ID!) {
user(id: $id) {
...UserNameFragment
}
}
`,
variables: id => ({id}),
mapResponse: response => {
const userFragment = readInlineData(userNameFragment, response.user);
return userFragment?.name;
},
})

预取 GraphQL

GraphQL 查询也可以使用 预取模式 来预取。

function CurrentUserInfo() {
const currentUserID = useRecoilValue(currentUserIDState);
const userInfo = useRecoilValue(userInfoQuery(currentUserID));

const changeUser = useRecoilCallback(({snapshot, set}) => userID => {
// pre-fetch user info
snapshot.getLoadable(userInfoQuery(userID));

// change current user to start new render
set(currentUserIDState, userID);
});

return (
<div>
<h1>{userInfo.name}</h1>
<ul>
{userInfo.friends.map(friend =>
<li key={friend.id} onClick={() => changeUser(friend.id)}>
{friend.name}
</li>
)}
</ul>
</div>
);
}

预加载的 GraphQL

如果你使用的是 EntryPoints,那么你可以将查询与加载页面的大部分 JS 并行预加载。

首先,确保你在应用程序根目录为你的预加载查询 注册 EnvironmentKey

export const preloadedEnvironmentKey = new EnvironmentKey('preloaded');

export function AppRoot() {
const preloadedEnvironment = useRelayEnvironment();
return (
<RecoilRoot>
<RecoilRelayEnvironment
environmentKey={preloadedEnvironmentKey}
environment={preloadedEnvironment}>
{/* My App */}
</RecoilRelayEnvironment>
</RecoilRoot>
)
}

然后,将你的查询定向到使用此 preloadedEnvironmentKey,并在 GraphQL 中添加 @preloadable 装饰器

export const userQuery = graphQLSelector({
key: 'UserQuery',
environmentKey: preloadedEnvironmentKey,
query: graphql`
query UserQuery($id: ID!) @preloadable {
user(id: $id) {
name
}
}
`,
variables: ({get}) => ({id: get(currentIDAtom)}),
mapResponse: data => data?.user,
});

最后,将此查询添加到 *.entrypoint.js 文件中的预加载查询中

const MyEntryPoint = {
getPreloadProps: params => ({
queries: {
userQuery: {
parameters: require('UserQuery$Parameters'),
variables: {id: params.id},
},
}),
root: JSResource('m#MyApp.react'),
};