mirror of
https://github.com/vercel/next.js.git
synced 2026-09-20 02:25:18 +08:00
93c59f02f8
## For Contributors ### Fixing a bug - Fixes #(open or reference an issue if one exists, otherwise omit) - No tests required — this is an `examples/` change only - No custom error links needed — failures are surfaced via Apollo's built-in error state --- ## Summary - `PostList` destructured `data` before checking `loading`/`error`, so the component threw when `data` was `undefined` (e.g., on the initial fetch or after a query error) instead of showing the loading/error UI. - Move the `error`/`loading`/`!data` guard clauses above the `data` destructuring and `loadMorePosts` definition, and add a `!data` check so the component never accesses properties on an undefined value. - Bump `graphql` (`14.5.8` → `16.13.1`) and `lodash` (`4.17.20` → `4.17.23`) in the example's `package.json` to pick up fixes in dependencies the example relies on. ## Note: Initially this PR suppose to target upstream DB issue
113 lines
2.7 KiB
JavaScript
113 lines
2.7 KiB
JavaScript
import { gql, useQuery, NetworkStatus } from "@apollo/client";
|
|
import ErrorMessage from "./ErrorMessage";
|
|
import PostUpvoter from "./PostUpvoter";
|
|
|
|
export const ALL_POSTS_QUERY = gql`
|
|
query allPosts($first: Int!, $skip: Int!) {
|
|
allPosts(orderBy: { createdAt: desc }, first: $first, skip: $skip) {
|
|
id
|
|
title
|
|
votes
|
|
url
|
|
createdAt
|
|
}
|
|
_allPostsMeta {
|
|
count
|
|
}
|
|
}
|
|
`;
|
|
export const allPostsQueryVars = {
|
|
skip: 0,
|
|
first: 10,
|
|
};
|
|
|
|
export default function PostList() {
|
|
const { loading, error, data, fetchMore, networkStatus } = useQuery(
|
|
ALL_POSTS_QUERY,
|
|
{
|
|
variables: allPostsQueryVars,
|
|
// Setting this value to true will make the component rerender when
|
|
// the "networkStatus" changes, so we are able to know if it is fetching
|
|
// more data
|
|
notifyOnNetworkStatusChange: true,
|
|
},
|
|
);
|
|
|
|
const loadingMorePosts = networkStatus === NetworkStatus.fetchMore;
|
|
|
|
if (error) return <ErrorMessage message="Error loading posts." />;
|
|
if (loading && !loadingMorePosts) return <div>Loading</div>;
|
|
if (!data) return null;
|
|
|
|
const { allPosts, _allPostsMeta } = data;
|
|
|
|
const loadMorePosts = () => {
|
|
fetchMore({
|
|
variables: {
|
|
skip: allPosts.length,
|
|
},
|
|
});
|
|
};
|
|
|
|
const areMorePosts = allPosts.length < _allPostsMeta.count;
|
|
|
|
return (
|
|
<section>
|
|
<ul>
|
|
{allPosts.map((post, index) => (
|
|
<li key={post.id}>
|
|
<div>
|
|
<span>{index + 1}. </span>
|
|
<a href={post.url}>{post.title}</a>
|
|
<PostUpvoter id={post.id} votes={post.votes} />
|
|
</div>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
{areMorePosts && (
|
|
<button onClick={() => loadMorePosts()} disabled={loadingMorePosts}>
|
|
{loadingMorePosts ? "Loading..." : "Show More"}
|
|
</button>
|
|
)}
|
|
<style jsx>{`
|
|
section {
|
|
padding-bottom: 20px;
|
|
}
|
|
li {
|
|
display: block;
|
|
margin-bottom: 10px;
|
|
}
|
|
div {
|
|
align-items: center;
|
|
display: flex;
|
|
}
|
|
a {
|
|
font-size: 14px;
|
|
margin-right: 10px;
|
|
text-decoration: none;
|
|
padding-bottom: 0;
|
|
border: 0;
|
|
}
|
|
span {
|
|
font-size: 14px;
|
|
margin-right: 5px;
|
|
}
|
|
ul {
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
button:before {
|
|
align-self: center;
|
|
border-style: solid;
|
|
border-width: 6px 4px 0 4px;
|
|
border-color: #ffffff transparent transparent transparent;
|
|
content: "";
|
|
height: 0;
|
|
margin-right: 5px;
|
|
width: 0;
|
|
}
|
|
`}</style>
|
|
</section>
|
|
);
|
|
}
|