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'),
};