GraphQL 是一个用于 API 的查询语言,可以让客户端精确地请求需要的数据,而不是像 REST API 那样返回大量不必要的数据。在前端开发中,使用 GraphQL 可以提高应用程序的性能和可维护性。而在 JavaScript 中,有两个主要的 GraphQL 客户端库:Apollo 和 Relay。
Apollo
Apollo 是一个流行的 GraphQL 客户端库,它提供了一系列功能,包括缓存、分页、错误处理和实时更新等。使用 Apollo 可以轻松地将 GraphQL 查询集成到 JavaScript 应用程序中。
安装
要使用 Apollo,需要安装 apollo-client
和 graphql
两个依赖项:
npm install apollo-client graphql
基本用法
使用 Apollo 的第一步是创建一个 ApolloClient
实例,并将其连接到 GraphQL 服务器:
// javascriptcn.com 代码示例 import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'; import { setContext } from '@apollo/client/link/context'; const httpLink = createHttpLink({ uri: 'http://localhost:4000/graphql' }); const authLink = setContext((_, { headers }) => { const token = localStorage.getItem('token'); return { headers: { ...headers, authorization: token ? `Bearer ${token}` : '' } }; }); const client = new ApolloClient({ link: authLink.concat(httpLink), cache: new InMemoryCache() });
在这个例子中,我们使用了 createHttpLink
来创建一个连接到 GraphQL 服务器的链接,并使用 setContext
将用户的 JWT 认证令牌添加到请求头中。最后,我们创建了一个 ApolloClient
实例,并将链接和缓存传递给它。
接下来,我们可以使用 useQuery
钩子来发送查询并获取数据:
// javascriptcn.com 代码示例 import { useQuery, gql } from '@apollo/client'; const GET_USERS = gql` query getUsers { users { id name email } } `; function UserList() { const { loading, error, data } = useQuery(GET_USERS); if (loading) return <p>Loading...</p>; if (error) return <p>Error :(</p>; return ( <ul> {data.users.map(user => ( <li key={user.id}>{user.name} ({user.email})</li> ))} </ul> ); }
在这个例子中,我们使用了 gql
函数来定义一个名为 getUsers
的查询,并使用 useQuery
钩子来发送查询并获取数据。我们还检查了 loading
和 error
属性以处理异步操作的状态。
缓存
Apollo 还提供了缓存功能,可以在多个组件之间共享数据。缓存是根据查询结果自动生成的,可以在查询时自动使用缓存数据,而不必每次都向服务器发出请求。在某些情况下,缓存可以大大提高应用程序的性能。
// javascriptcn.com 代码示例 import { useQuery, gql } from '@apollo/client'; const GET_USER = gql` query getUser($userId: ID!) { user(id: $userId) { id name email } } `; function UserProfile({ userId }) { const { loading, error, data } = useQuery(GET_USER, { variables: { userId }, fetchPolicy: 'cache-and-network' }); if (loading) return <p>Loading...</p>; if (error) return <p>Error :(</p>; return ( <div> <h2>{data.user.name}</h2> <p>Email: {data.user.email}</p> </div> ); }
在这个例子中,我们使用了 fetchPolicy: 'cache-and-network'
来告诉 Apollo 在查询时同时使用缓存和网络请求。这意味着如果缓存中已经有数据,Apollo 将首先返回缓存数据,然后再向服务器发出请求来更新数据。
实时更新
Apollo 还提供了实时更新功能,可以在服务器更新数据时立即更新客户端。这可以使用 useSubscription
钩子来实现。
// javascriptcn.com 代码示例 import { useSubscription, gql } from '@apollo/client'; const NEW_MESSAGE = gql` subscription newMessage { newMessage { id text createdAt } } `; function MessageList() { const { loading, error, data } = useSubscription(NEW_MESSAGE); if (loading) return <p>Loading...</p>; if (error) return <p>Error :(</p>; return ( <ul> {data.newMessage.map(message => ( <li key={message.id}>{message.text}</li> ))} </ul> ); }
在这个例子中,我们使用了 useSubscription
钩子来订阅 newMessage
事件,并在服务器更新数据时立即更新客户端。这可以让我们构建实时聊天应用程序等实时应用程序。
Relay
Relay 是 Facebook 开发的另一个流行的 GraphQL 客户端库,它专门为 React 应用程序设计。与 Apollo 不同,Relay 需要使用 GraphQL schema 来生成查询和缓存数据,并使用 GraphQL 编译器将查询转换为可执行的代码。
安装
要使用 Relay,需要安装 relay-compiler
、relay-runtime
和 babel-plugin-relay
三个依赖项:
npm install relay-compiler relay-runtime babel-plugin-relay
基本用法
使用 Relay 的第一步是创建一个 RelayEnvironment
实例,并将其连接到 GraphQL 服务器:
// javascriptcn.com 代码示例 import { Environment, Network, RecordSource, Store } from 'relay-runtime'; function fetchQuery(operation, variables) { return fetch('/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query: operation.text, variables }) }).then(response => { return response.json(); }); } const environment = new Environment({ network: Network.create(fetchQuery), store: new Store(new RecordSource()) });
在这个例子中,我们使用 fetchQuery
函数来发送 GraphQL 查询,并将其传递给 RelayEnvironment
实例。
接下来,我们需要定义一个 QueryRenderer
组件,并使用 createFragmentContainer
函数来定义查询的数据模型:
// javascriptcn.com 代码示例 import { QueryRenderer, graphql } from 'react-relay'; const UserList = ({ users }) => ( <ul> {users.map(user => ( <li key={user.id}>{user.name} ({user.email})</li> ))} </ul> ); const UserListFragment = createFragmentContainer(UserList, { users: graphql` fragment UserList_users on User @relay(plural: true) { id name email } ` }); const GET_USERS = graphql` query UserListQuery { users { ...UserList_users } } `; function App() { return ( <QueryRenderer environment={environment} query={GET_USERS} render={({ error, props }) => { if (error) return <div>Error!</div>; if (!props) return <div>Loading...</div>; return <UserListFragment users={props.users} />; }} /> ); }
在这个例子中,我们使用 QueryRenderer
组件来发送查询并获取数据。我们还使用 createFragmentContainer
函数来定义查询的数据模型,并在 UserList
组件中使用它来渲染用户列表。
缓存
与 Apollo 类似,Relay 也提供了缓存功能,可以在多个组件之间共享数据。缓存是根据查询结果自动生成的,可以在查询时自动使用缓存数据,而不必每次都向服务器发出请求。
// javascriptcn.com 代码示例 import { createPaginationContainer, graphql } from 'react-relay'; const UserList = ({ users, loadMore }) => ( <div> <ul> {users.map(user => ( <li key={user.id}>{user.name} ({user.email})</li> ))} </ul> <button onClick={loadMore}>Load more</button> </div> ); const UserListPagination = createPaginationContainer(UserList, { users: graphql` fragment UserList_users on User @relay(plural: true) { id name email } ` }, { direction: 'forward', getConnectionFromProps(props) { return props.users; }, getVariables(props, { count, cursor }, fragmentVariables) { return { ...fragmentVariables, count, cursor }; }, query: graphql` query UserListPaginationQuery( $count: Int!, $cursor: String ) { users( first: $count, after: $cursor ) @connection(key: "UserList_users") { pageInfo { hasNextPage endCursor } edges { node { ...UserList_users } } } } ` }); function App() { return ( <QueryRenderer environment={environment} query={GET_USERS} render={({ error, props }) => { if (error) return <div>Error!</div>; if (!props) return <div>Loading...</div>; return ( <UserListPagination users={props.users} loadMore={() => { const { endCursor } = props.users.pageInfo; const count = 10; UserListPagination.loadMore( environment, count, endCursor, { query: GET_USERS } ); }} /> ); }} /> ); }
在这个例子中,我们使用 createPaginationContainer
函数来定义分页查询,并在 UserList
组件中使用它来渲染用户列表。我们还使用 loadMore
函数来加载更多数据,并在查询时自动使用缓存数据,而不必每次都向服务器发出请求。
实时更新
Relay 还提供了实时更新功能,可以在服务器更新数据时立即更新客户端。这可以使用 requestSubscription
函数来实现。
// javascriptcn.com 代码示例 import { requestSubscription, graphql } from 'react-relay'; const NEW_MESSAGE = graphql` subscription newMessage { newMessage { id text createdAt } } `; function MessageList() { const [messages, setMessages] = useState([]); useEffect(() => { const subscription = requestSubscription( environment, { subscription: NEW_MESSAGE, variables: {}, updater: store => { const newMessage = store.getRootField('newMessage'); setMessages([...messages, newMessage]); } } ); return () => { subscription.dispose(); }; }, []); return ( <ul> {messages.map(message => ( <li key={message.id}>{message.text}</li> ))} </ul> ); }
在这个例子中,我们使用 requestSubscription
函数来订阅 newMessage
事件,并在服务器更新数据时立即更新客户端。我们还使用 useEffect
钩子来启动订阅,并在组件卸载时停止订阅。
总结
Apollo 和 Relay 都是流行的基于 JavaScript 的 GraphQL 客户端库,提供了一系列功能,包括缓存、分页、错误处理和实时更新等。使用这些客户端库可以轻松地将 GraphQL 查询集成到 JavaScript 应用程序中,并提高应用程序的性能和可维护性。无论选择哪个客户端库,都需要根据具体的应用程序需求来选择。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6507c5e895b1f8cacd303b58