Мы создали наш блог на Next JS, используя WordPress в качестве нашего API, мы добавляли контент, пока не превысили 500, и наш блог продолжал зависать, потому что нам приходилось вызывать все сообщения нашего блога одновременно с сервера.
Мы намерены создать функцию кнопки разбивки на страницы «Загрузить больше», которая при нажатии вызывает только определенное количество объектов за раз.
Вот как выглядит наш код.
//index.tsx
/**
* Caution: Consider this file when using NextJS or GatsbyJS
*
* You may delete this file and its occurrences from the project filesystem if you are using react-scripts
*/
import React from 'react';
import BlogSearch from 'views/BlogSearch';
import Main from 'layouts/Main';
import WithLayout from 'WithLayout';
import Head from 'next/head';
import { getBlogPosts } from '../../lib/api';
const BlogPage = ({ posts }): JSX.Element => {
return (
<>
{' '}
<Head>
<title>Copy and Post - Blog</title>
<meta
property = "og:title"
content = "Copy and Post - Blog"
key = "Copy and Post"
/>
</Head>
<WithLayout
component = {() => <BlogSearch posts = {posts} />}
layout = {Main}
/>
</>
);
};
export default BlogPage;
export async function getStaticProps() {
const posts = await getBlogPosts();
return {
props: {
...posts,
},
};
}
//api.ts
import { homepageQuery, blogPosts, blogPostBySlug } from './queries';
const API_URL = process.env.WP_API_URL;
async function fetchAPI(query, { variables = {} } = {}) {
// Set up some headers to tell the fetch call
// that this is an application/json type
const headers = { 'Content-Type': 'application/json' };
// build out the fetch() call using the API_URL
// environment variable pulled in at the start
// Note the merging of the query and variables
const res = await fetch(API_URL, {
method: 'POST',
headers,
body: JSON.stringify({ query, variables }),
});
// error handling work
const json = await res.json();
if (json.errors) {
console.info(json.errors);
console.info('error details', query, variables);
throw new Error('Failed to fetch API');
}
return json.data;
}
export async function getHomepageSections() {
const data = await fetchAPI(homepageQuery);
return data;
}
export async function getBlogPosts() {
const data = await fetchAPI(blogPosts);
return data;
}
export async function getBlogPostBySlug(slug) {
const data = await fetchAPI(blogPostBySlug, { variables: { id: slug } });
return data;
}
//query.ts
export const homepageQuery = `
query HomepageQuery {
homepageSections {
edges {
node {
homepage {
hero {
animatedwords
heading
subtitle
}
callouts {
title
subtitle
calloutone {
title
subtext
image {
mediaItemUrl
}
}
calloutthree {
title
subtext
image {
mediaItemUrl
}
}
callouttwo {
title
subtext
image {
mediaItemUrl
}
}
}
icongrid {
iconone {
description
icon
title
}
iconfive {
description
icon
title
}
iconfour {
description
icon
title
}
iconsix {
description
icon
title
}
iconthree {
description
icon
title
}
icontwo {
description
icon
title
}
}
}
}
}
}
}
`;
export const blogPosts = `
query BlogPosts {
posts(first: 1000) {
edges {
node {
author {
node {
nickname
}
}
date
slug
featuredImage {
node {
mediaItemUrl
}
}
title
}
}
}
}
`;
export const blogPostBySlug = `
query PostBySlug($id: ID!) {
post(id: $id, idType: SLUG) {
id
content
title
author {
node {
nickname
avatar {
url
}
}
}
date
featuredImage {
node {
mediaItemUrl
}
}
}
}
`;
🤔 А знаете ли вы, что...
С React можно легко интегрировать с существующими проектами и кодом.
Реализация нумерации страниц по принципу «загрузи больше» — непростая задача. Я просто дам базовый обзор того, как это можно реализовать как на стороне клиента, так и на стороне сервера.
Серверная часть
У вас должна быть конечная точка API, которая принимает параметры limit
и startAfter
. по умолчанию, когда пользователь запрашивает без параметров startAfter
, возвращаются блоги в качестве ограничения.
если параметр startAfter
доступен, отправьте в блоги те идентификаторы, которые идут после значения startAfter
.
/blogs?limit=10 => return top 10 blogs
/blogs?limit=10&startAfter=10 => return next 10 blogs (where 10 is last blog id)
Сторона клиента
На стороне клиента извлеките несколько начальных блогов с помощью функции getStaticProps
, а затем всякий раз, когда пользователь завершает прокрутку или нажимает кнопку «Загрузить еще», извлекайте новые блоги, отправляя параметр startAfter
. прекратите запрашивать, если сервер отправляет обратно пустой массив.
export default function Blogs({ posts }) {
const [blogs, setBlogs] = useState(posts)
const loadMorePost = useCallback(() => {
const makeReq = async ()=> {
const res = await fetch(`/blogs?limit=10&startAt=${blogs.at(-1).id}`)
const json = await res.json()
// TODO: stop fetching if response is empty array
setBlogs(blogs => [...json, blogs])
}
}, [blogs])
return <>
{/* ... */}
<button onClick = {loadMorePost}>load more</button>
</>
}
Приложение
для справки вы можете проверить, как я реализовал нумерацию страниц в своем приложении.
Я думаю, вы можете использовать смещение и ограничение в качестве переменных для вашего внутреннего запроса. что-то вроде этого (не уверен, называется ли это offset
или startAfter
):
posts(offset: $offset, limit: $limit) {
и внутреннюю функцию API следует изменить, чтобы разрешить эти параметры.
export async function getBlogPosts(offset, limit) {
const data = await fetchAPI(blogPosts, { variables: { offset, limit} });
return data;
}
и сохраните текущую страницу на стороне клиента. на стороне клиента, если вы нажмете кнопку «Загрузить больше», вы можете выполнить расчет лимитов следующим образом:
const PAGE_SIZE = 100
let current_page = 0
export async function getStaticProps() {
current_page += 1
const offset = PAGE_SIZE * current_page
const limit = offset + PAGE_SIZE
const posts = await getBlogPosts(offset, limit );
return ...
Спасибо всем за ваши предложения, но вот как я наконец решил эту проблему.
# queries.ts
let condition = `after: "${endCursor}",first: 12, where: {orderby: {field: DATE, order: DESC}}`
export const blogPosts = `
query BlogPosts {
posts(${condition}) {
edges {
node {
author {
node {
nickname
}
}
date
slug
featuredImage {
node {
mediaItemUrl
}
}
title
}
}
pageInfo {
endCursor
hasNextPage
hasPreviousPage
startCursor
}
}
}
`;
Api.ts
export async function getBlogPosts(endCursor = null, taxonomy = null) {
const data = await fetchAPI(blogPosts);
return data;
}
#LoadMore.ts
import React from 'react';
import { getBlogPosts } from '../../../../lib/api';
const LoadMore = ({posts, setPosts}) => {
const handleOnclick = async(event) =>{
const morePosts = await getBlogPosts(posts.pageInfo.endCursor)
let updatedPosts = {
pageInfo: {
},
nodes: []
}
updatedPosts.pageInfo = morePosts.pageInfo;
posts.nodes.map((node) => {
updatedPosts.nodes.push(node);
});
morePosts.nodes.map((node) => {
updatedPosts.nodes.push(node);
});
setPosts(updatedPosts);
}
return (
<>
<button
onClick = {handleOnclick}
>
Load More
</button>
</>
);
};
export default LoadMore;
Для получения дополнительной информации мне помогли с этим видео на YouTube.
https://thewikihow.com/video_HI_tZRIfhIw&list=PLHYTWh7vcn_D36jk_L93NTOb0B5sqgjxX&index=3&t=1167s