面试题:Nextjs写一个博客

185 阅读3分钟

题目

题目:基于 Next.js 实现的服务端渲染博客页面

问题描述:

请使用 Next.js 构建一个简单的博客页面,页面将显示从外部 API 获取的博客文章数据。具体要求如下:

使用 getServerSideProps 获取并渲染从外部 API 获取的博客文章列表。

每篇文章包含标题和内容的简短摘要。

点击文章标题后,用户应被导航到一个 动态路由页面,展示该文章的完整内容。

在文章详情页中,实现一个 “返回” 按钮,用户可以点击此按钮返回到博客列表页面。

外部 API 示例:

您可以使用以下 API 模拟外部数据源:

url Copy code jsonplaceholder.typicode.com/posts>

该 API 返回的每篇文章数据格式为:

{
"userId": 1,
"id": 1,
"title": "文章标题",
"body": "文章内容"
}

要求:

使用 Next.js 的 getServerSideProps 实现服务端渲染,获取博客数据并渲染到页面中。

在博客列表页中,每篇文章只显示标题和内容的前 20 个字符作为摘要。

实现动态路由:点击文章标题后跳转到 /posts/[id] 动态路由页面,显示文章完整内容。

提供代码注释,并确保结构清晰。

思考

给大家一个思考的时间,看看遇到这样的面试题自己应该怎么写

我的思考逻辑:

  • 创建nextjs项目

  • 博客首页使用getServerSideProps获取数据并使用useContext存储数据

  • 动态路由进行跳转,Nextjs也是支持的,获取数据并筛选。

创建Next.js项目

首先,确保你已经安装了 Next.js 和其他相关依赖。你可以通过以下命令创建一个新的 Next.js 项目:

npx create-next-app@latest next-blog
cd next-blog
npm install

创建Context

// context/PostContext.js
import { createContext, useContext, useState } from "react";
const PostContext = createContext();
export function PostProvider({ children }) {
  const [posts, setPosts] = useState([]);
  return (
    <PostContext.Provider value={{ posts, setPosts }}>
      {children}
    </PostContext.Provider>
  );
}

export function usePostContext() {
  return useContext(PostContext);
}

_app.js 中包装全局状态


// pages/_app.js
import { PostProvider } from "../context/PostContext";

function MyApp({ Component, pageProps }) {
  return (
    <PostProvider>
      <Component {...pageProps} />
    </PostProvider>
  );
}

export default MyApp;

在首页获取数据并存入 Context


// pages/index.js
import Link from "next/link";

import { usePostContext } from "../context/PostContext";

export default function Home({ postsData }) {
  const { setPosts } = usePostContext();

  // 存入 context

  setPosts(postsData);

  return (
    <div>
      <h1>Blog Posts</h1>
      <ul>
        {postsData.map((post) => (
          <li key={post.id}>
            <Link href={`/posts/${post.id}`}>
              <a>
                <h2>{post.title}</h2>

                <p>{post.body.slice(0, 20)}...</p>
              </a>
            </Link>
          </li>
        ))}
      </ul>
    </div>
  );
}

export async function getServerSideProps() {
  const res = await fetch("<https://jsonplaceholder.typicode.com/posts");

  const postsData = await res.json();

  return {
    props: {
      postsData,
    },
  };
}

在文章详情页中获取 Context 中的文章数据


// pages/posts/[id].js
import { useRouter } from "next/router";
import { usePostContext } from "../../context/PostContext";
import Link from "next/link";

export default function Post() {
  const router = useRouter();
  const { posts } = usePostContext();
  const { id } = router.query;
  const post = posts.find((p) => p.id.toString() === id);
  if (!post) {
    return <div>Post not found</div>;
  }

  return (
    <div>
      <h1>{post.title}</h1>

      <p>{post.body}</p>

      <Link href="/">
        <a>← Back to home</a>
      </Link>
    </div>
  );
}

目录结构

nextjs-blog/

├── components/
│ └── Navbar.js # 其他可复用的组件
├── context/
│ └── PostContext.js # 用于管理博客文章的全局状态
├── pages/
│ ├── posts/
│ │ └── [id].js # 动态路由页面,展示文章详情
│ ├── _app.js # 全局入口,注入 Context Provider
│ ├── index.js # 博客首页,显示文章列表
├── public/
│ └── favicon.ico # 公共资源文件
├── styles/
│ └── globals.css # 全局样式文件
├── package.json # 项目依赖文件
├── README.md # 项目说明文件
├── next.config.js # Next.js 配置文件

结尾

很简单吧,重点就是怎么传输我们获取的数据,当然除了useContext这种方法我们还有很多其他的方法可以使用。比如SessionStorageLocalStorageReduxURL HashuseRouter


如果大家有任何疑问,欢迎随时在评论区提出,或者直接私聊我探讨交流!我非常愿意和大家一起讨论这些技术问题。如果我的解答有任何不准确的地方,也请大家及时指出,我会积极改正并完善内容。

你们的支持如同璀璨星光,照亮我前行的创作之路,让我更有信心和热情为大家带来更多优质的内容。