如果你要将你的React前端与GraphQL API集成,你可能想看看Apollo客户端!我发现它的连接非常简单。我发现它是非常直接的连接。
在这篇文章中,我们将使用create-react-app ,从头开始创建一个React项目,加入Apollo GraphQL客户端,然后使用SpaceX GraphQL API在我们的应用程序中显示数据。
创建一个新的React应用程序
我将使用yarn 包管理器来创建一个新的React应用程序,名为react-with-apollo 。当然,如果你愿意,你可以使用npm 。
yarn create react-app react-with-apollo
我们可以cd ,进入该目录并运行yarn start ,以确保我们的默认React应用在端口3000上运行。
cd react-with-apollo
yarn start
如果我们导航到http://localhost:3000,我们会得到这样的东西。
添加GraphQL到Apollo客户端
为了使用GraphQL和Apollo客户端,我们需要把它们都作为项目依赖来安装。让我们用yarn来做这件事。
yarn add graphql @apollo/client
接下来我们需要做的是配置Apollo客户端。通常,这可能需要与你的GraphQL服务器进行认证,但由于SpaceX的API是公开的,我们不需要担心这个问题。相反,我们只需要用我们的GraphQL API端点配置客户端。我们还可以指定我们想为我们的查询做的任何缓存。在这个基本的例子中,我们只是做一些内存缓存。
在这个例子中,我们将在我们的index.js 文件中配置我们的客户端,并将我们的App 纳入Apollo提供者。在实践中,你可能应该把你的Apollo提供者作为任何需要从GraphQL API获取数据的组件的最低共同祖先。
index.html
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';
const client = new ApolloClient({
uri: 'https://api.spacex.land/graphql/',
cache: new InMemoryCache(),
});
ReactDOM.render(
<React.StrictMode>
<ApolloProvider client={client}>
<App />
</ApolloProvider>
</React.StrictMode>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
查询API
我们现在已经准备好查询API了!在我们的。在我们的App.js 文件中,让我们创建一个查询,获取 SpaceX 过去的任务,包括日期、发射地点和火箭。当然,由于这是GraphQL,在一个查询中获取所有这些信息是微不足道的。
我们将在我们的查询中包括一个变量,numLaunches ,这样我们就可以看到如何使用变量。
App.js
import { gql } from '@apollo/client';
const PAST_LAUNCHES = gql`
query GetPastLaunces($numLaunches: Int!) {
launchesPast(limit: $numLaunches) {
mission_name
launch_date_local
launch_site {
site_name_long
}
rocket {
rocket_name
}
}
}
`;
function App() {
// TBD
}
现在是我们整合Apollo客户端的部分。它有一个非常方便的useQuery 钩子,为我们做了很多重活。基本上,我们传递我们刚刚定义的查询,以及任何查询选项(在我们的例子中,只是变量),然后钩子返回一个loading 布尔值,可能是一个error 对象,以及返回的data 。
import { gql, useQuery } from '@apollo/client';
const PAST_LAUNCHES = gql`
query GetPastLaunces($numLaunches: Int!) {
launchesPast(limit: $numLaunches) {
mission_name
launch_date_local
launch_site {
site_name_long
}
rocket {
rocket_name
}
}
}
`;
function App() {
const { loading, error, data } = useQuery(PAST_LAUNCHES, {
variables: {
numLaunches: 10,
},
});
}
在这里我们可以看到,我们已经提供了我们的PAST_LAUNCHES 查询和我们的numLaunches 参数,我们现在已经把它设置为10 。
那么--让我们使用钩子返回给我们的信息吧!由于我们现在只是在学习,我们将有一个非常简单的互动。true如果loading ,我们会向用户显示一个 "正在加载... "的信息,如果error ,我们会告诉用户出了问题,否则,我们会以可读的方式格式化我们的查询数据。
import { gql, useQuery } from '@apollo/client';
const PAST_LAUNCHES = gql`
query GetPastLaunces($numLaunches: Int!) {
launchesPast(limit: $numLaunches) {
mission_name
launch_date_local
launch_site {
site_name_long
}
rocket {
rocket_name
}
}
}
`;
function App() {
const { loading, error, data } = useQuery(PAST_LAUNCHES, {
variables: {
numLaunches: 10,
},
});
if (loading) {
return <p>Loading...</p>;
}
if (error) {
return <p>Oh no!</p>;
}
return (
<ul>
{data.launchesPast.map((launch) => (
<li key={launch.mission_name}>
<strong>{launch.mission_name}</strong>
<ul>
<li>
Launch Date:{' '}
{new Date(launch.launch_date_local).toLocaleDateString()}
</li>
<li>Rocket: {launch.rocket.rocket_name}</li>
<li>Launch Site: {launch.launch_site.site_name_long}</li>
</ul>
</li>
))}
</ul>
);
}
export default App;
当然,我们的data 的结构与我们的输入查询的结构完全相同;这是更有用的GraphQL功能之一
让我们检查一下我们的网络应用,看看事情看起来是否正常。
完美!我觉得很好。对我来说,看起来很好。
更新变量
在这篇文章的最后一部分,让我们探讨一下,如果我们更新我们的变量,重新获取数据是多么容易。在这种情况下,我们可能想要一个不同的过去发射的数量。
我们的希望可能是,我们可以只维护一个单独的numLaunches 有状态的变量,当我们更新这个变量时,我们可以使teuseQuery 钩子再次启动。在下面的例子中,我们只是添加一个按钮来显示5次发射,而不是10次。这很微不足道,但你会明白的
import { gql, useQuery } from '@apollo/client';
import { useState } from 'react';
const PAST_LAUNCHES = gql`
query GetPastLaunces($numLaunches: Int!) {
launchesPast(limit: $numLaunches) {
mission_name
launch_date_local
launch_site {
site_name_long
}
rocket {
rocket_name
}
}
}
`;
function App() {
const [numLaunches, setNumLaunches] = useState(10);
const { loading, error, data } = useQuery(PAST_LAUNCHES, {
variables: {
numLaunches,
},
});
if (loading) {
return <p>Loading...</p>;
}
if (error) {
return <p>Oh no!</p>;
}
return (
<>
<button onClick={() => setNumLaunches(5)}>Show 5</button>
<ul>
{data.launchesPast.map((launch) => (
<li key={launch.mission_name}>
<strong>{launch.mission_name}</strong>
<ul>
<li>
Launch Date:{' '}
{new Date(launch.launch_date_local).toLocaleDateString()}
</li>
<li>Rocket: {launch.rocket.rocket_name}</li>
<li>Launch Site: {launch.launch_site.site_name_long}</li>
</ul>
</li>
))}
</ul>
</>
);
}
export default App;
那么,这是否有效呢?让我们测试一下。
你打赌它是有效的
结论性的想法
我非常喜欢带有React的Apollo客户端。在执行GraphQL查询时,它能 "正常工作 "并提供我需要的反应性。希望这篇文章也能帮助你在React中开始使用GraphQL!