nextjs(持续学习中),深入剖析反面典型案例

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Web前端全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024c (备注前端)
img

正文

});


在/app/layout.tsx文件中将字体添加到以下 元素中



/**
* 通过添加到 Inter 元素中 ,字体将应用于整个应用程序。
* 在这里,您还添加了 Tailwind antialiased 类,该类使字体平滑。
* 没有必要使用这个类,但它增加了一个很好的触感。
* 导航到浏览器,打开开发工具并选择 body 元素。
* 您应该看到 Inter 并且 Inter_Fallback 现在已应用在样式下
*/
import ‘@/app/ui/global.css’;
// 导入字体
import { inter } from ‘@/app/ui/fonts’;
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (

{/* {children} */}
{/* 使用字体 */}
<body className={${inter.className} antialiased}>{children}

);
}


在 /app/page.tsx 文件中找到的 


 元素,使用辅助字体。



// 使用辅助字体
import { lusitana } from ‘@/app/ui/fonts’;

export default function Page() {
return (
<p className={${lusitana.className} text-xl text-gray-800 md:text-3xl md:leading-normal}>
Welcome to Acme. This is the example for the{’ '}

Next.js Learn Course

, brought to you by Vercel.


);
}

在顶级 /public 文件夹下提供静态资产  
 **默认 /public 文件夹会被映射网站的根目录**



> 
> 即/public/img.png -> /img.png
> 
> 
> 


使用常规 HTML(不推荐)



/**
* 使用常规 HTML,必须手动
* 确保您的图像在不同的屏幕尺寸上具有响应性
* 指定不同设备的图像大小
* 防止在加载图像时出现布局偏移
* 延迟加载用户视口之外的图像
* --------------------------------------------------
* 图像优化是 Web 开发中的一个大主题,本身可以被视为一个专业化。
* 您可以使用该 next/image 组件自动优化图像,而不是手动实现这些优化。
* ------------------------------
* 自动图像优化功能:
* 1、防止在加载图像时自动移动布局
* 2、调整图像大小以避免将大图像传送到视口较小的设备。
* 3、默认情况下延迟加载图像(图像在进入视口时加载->懒加载)。
* 4、在浏览器支持的情况下,以现代格式(如 WebP 和 AVIF)提供图像。
*
**/

Screenshots of the dashboard project showing desktop version


使用 next/image 组件自动优化图像(**推荐**)


在 /app/page.tsx 文件中,导入 next/image 组件。



> 
> 根据image 组件设置的宽高进行设定  
>  默认移动端优先原则,md: 更宽的屏幕 block:以块级元素显示  
>  className=“hidden md:block” 默认hidden 隐藏,md: 更宽的屏幕显示
> 
> 
> 



/**
* 应该设置图片的宽高(避免布局偏移(从无到有))
* 宽高应该与原图的纵横比相同
* 您还会注意到该类 hidden 用于从移动屏幕上的 DOM 中删除图像
* md:block 桌面屏幕上显示图像。
**/
import Image from ‘next/image’;
export default function Page() {
return (


{/* Add Hero Images Here */}
Screenshots of the dashboard project showing desktop version
{/* 显示在移动屏幕上,并在桌面上隐藏 */}
Screenshot of the dashboard project showing mobile version

);
}


### 创建布局和页面




| 特殊文件 | 说明 |
| --- | --- |
| page.tsx | 用于导出 React 组件,并且路由是可访问所必需的(不同文件下访问入口) |
| layout.tsx | 布局文件(不同文件下的布局入口) |
| loading.tsx | 创建后备 UI 以在页面内容**加载时显示**为替换 |


创建首页入口文件:/app/dashboard/page.tsx  
 url地址:http://localhost:3000/dashboard



export default function Page() {
return

Dashboard Page

;
}

在Next.js中使用布局的一个好处是,在导航时,只有页面组件会更新,而布局不会重新呈现,这称为部分渲染。  
 创建首页布局文件:/app/dashboard/layout.tsx



import SideNav from ‘@/app/ui/dashboard/sidenav’;

export default function Layout({ children }: { children: React.ReactNode }) {
return (





{children}


);
}


### 页面导航



页面之间链接,通常使用 HTML 元素,每次切换页面都会被刷新。

在 Next.js 中,可以使用 组件在应用程序中的页面之间进行链接。

允许您使用 JavaScript 进行客户端导航。

**next/link 如何实现一个Web 应用?**


* Next.js会自动按路由段拆分应用程序。
* 这与传统的 React SPA 不同,在传统的 React SPA 中,浏览器在初始加载时加载所有应用程序代码
* 按路由拆分代码意味着页面变得独立。如果某个页面抛出错误,应用程序的其余部分仍将正常工作。
* 此外,在生产环境中,每当组件出现在浏览器的视口中时**Link**,Next.js都会在后台**自动预取链接路由的代码**。当用户单击链接时,目标页面的代码已经在后台加载,这就是使页面转换近乎即时的原因!


打开/app/ui/dashboard/nav-links.tsx文件, 导入 Link 组件。



// 使用Link
import Link from ‘next/link’;
// 然后,找到 标签替换为

{link.name}


获取用户的当前路径,Next.js提供了一个钩子函数usePathname()  
 使用客户端渲染(必须):作用于浏览器  
 默认情况下,Next.js应用程序使用 React Server 组件(服务端渲染)



‘use client’; // 使用客户端渲染(必须)
import {
UserGroupIcon,
HomeIcon,
DocumentDuplicateIcon,
} from ‘@heroicons/react/24/outline’;
// 导入钩子函数usePathname
import { usePathname } from ‘next/navigation’;
// usePathname搭配clsx使用
import clsx from ‘clsx’;
// 导航列表
const links = [
{ name: ‘Home’, href: ‘/dashboard’, icon: HomeIcon },
{
name: ‘Invoices’,
href: ‘/dashboard/invoices’,
icon: DocumentDuplicateIcon,
},
{ name: ‘Customers’, href: ‘/dashboard/customers’, icon: UserGroupIcon },
];

export default function NavLinks() {
const pathname = usePathname();
return (
<>
{links.map((link) => {
const LinkIcon = link.icon;
return (
<Link
key={link.name}
href={link.href}
className={clsx(
‘flex h-[48px] grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3’,
{
‘bg-sky-100 text-blue-600’: pathname === link.href,
},
)}
>

{link.name}



);
})}
</>
);
}

### 设置数据库


使用@vercel/postgres设置PostgreSQL数据库


1. 将项目推送到 GitHub
2. 设置 [Vercel]( ) 帐户并链接 GitHub 存储库以进行即时预览和部署
3. 创建项目并将其链接到Postgres 数据库



> 
> 在上传的项目中,选择Storage  
>  Connect Store → Create New → Postgres → Continue  
>  通过将数据库放置在同一区域或靠近应用程序代码,可以减少数据请求的延迟。  
>  数据库区域一旦启动就无法更改。如果要使用其他区域,则应在创建数据库之前进行设置  
>  导航到 .env.local 选项卡,单击“显示密钥”和“复制代码段”  
>  导航到代码编辑器并将 .env.example 文件重命名为 .env 。粘贴从 Vercel 复制的内容。  
>  重要提示:转到您的 .gitignore 文件并确保 .env 位于忽略的文件中,以防止在推送到 GitHub 时暴露您的数据库机密。  
>  最后,在终端中运行 npm i @vercel/postgres 以安装 Vercel Postgres SDK。
> 
> 
> 


4. 使用初始数据为数据库设定种子  
 文件中 package.json ,将以下行添加到脚本中



“scripts”: {
“build”: “next build”,
“dev”: “next dev”,
“start”: “next start”,
// this
“seed”: “node -r dotenv/config ./scripts/seed.js”
},


在终端运行:npm run seed  
 将placeholder-data.js数据导入数据库中(初始数据)  
 在Vercel查看数据是否填充完毕,选择Storage,下滑找到侧边栏Data,可查询表格,以及sql查询


### 获取数据


1. 了解一些获取数据的方法:API、ORM、SQL 等。
2. 服务器组件如何帮助您更安全地访问后端资源。
3. 什么是网络瀑布。
4. 如何使用 JavaScript 模式实现并行数据获取。


API 是应用程序代码和数据库之间的中间层


* 第三方提供的api
* 如果要从客户端提取数据,则希望在服务器上运行一个 API 层,以避免向客户端公开数据库机密。(在客户端上获取数据时不应直接查询数据库,因为这会暴露数据库机密。)
* 使用[route-handlers]( ) 创建 API 终端节点



> 
> 注:如果你使用的是 React Server 组件(在服务器上获取数据),你可以跳过 API 层,直接查询你的数据库,而不会冒着将数据库机密暴露给客户端的风险。
> 
> 
> 


**React Server 组件优点**


1. 服务器组件支持 Promise,为数据获取等异步任务提供更简单的解决方案。 您可以使用 async/await 语法,而无需使用 useEffect、useState 或数据获取库。
2. 服务器组件在服务器上执行,因此您可以将昂贵的数据提取和逻辑保留在服务器上,并且只将结果发送到客户端。
3. 如前所述,由于服务器组件在服务器上执行,因此您可以直接查询数据库,而无需额外的 API 层。


在/app/lib/data.ts文件中,导入 sql 函数,此函数允许您查询数据库



// 查询数据库
import { sql } from ‘@vercel/postgres’;


在/app/dashboard/page.tsx文件中



/**
* Page 是一个异步组件。这允许您用于 await 获取数据。
* 还有 3 个接收数据的组件: 、 和 。
* 它们目前被注释掉,以防止应用程序出错。
*
*/
import { Card } from ‘@/app/ui/dashboard/cards’;
import RevenueChart from ‘@/app/ui/dashboard/revenue-chart’;
import LatestInvoices from ‘@/app/ui/dashboard/latest-invoices’;
import { lusitana } from ‘@/app/ui/fonts’;

export default async function Page() {
return (

<h1 className={${lusitana.className} mb-4 text-xl md:text-2xl}>
Dashboard


{/* */}
{/* */}
{/* */}
{/* */}


{/* */}
{/* */}


);
}


在/app/lib/data.ts文件中引入fetchRevenue 函数  
 然后,取消对组件的 注释  
 导航到组件文件 ( /app/ui/dashboard/revenue-chart.tsx ) 并取消注释其中的代码。  
 检查你的 localhost,你应该能够看到一个使用 revenue 数据的图表。  
 …  
 后续相关自行查看官方文档



import { Card } from ‘@/app/ui/dashboard/cards’;
import RevenueChart from ‘@/app/ui/dashboard/revenue-chart’;
import LatestInvoices from ‘@/app/ui/dashboard/latest-invoices’;
import { lusitana } from ‘@/app/ui/fonts’;
// 获取数据
import { fetchRevenue } from ‘@/app/lib/data’;

export default async function Page() {
// 获取数据库数据
const revenue = await fetchRevenue();
// …
}


注意:


1. 数据请求无意中相互阻塞,从而创建了一个请求瀑布(同步)。



> 
> “瀑布流”是指一系列网络请求,这些请求依赖于先前请求的完成情况。在数据获取的情况下,每个请求只能在前一个请求返回数据后开始。(影响性能)  
>  `--------------------------------------------------------------------------`  
>  避免瀑布的常用方法是同时并行启动所有数据请求。(异步)  
>  在 JavaScript 中,您可以使用 Promise.all() or Promise.allSettled() 函数同时启动所有 promise。例如,在 中 data.ts ,我们在 fetchCardData() 函数中使用 Promise.all()  
>  开始同时执行所有数据提取,这可能会导致性能提升  
>  但是,仅依赖这种 JavaScript 模式有一个缺点:如果一个数据请求比其他所有数据请求慢,会发生什么情况?
> 
> 
> 


2. 默认情况下,Next.js预渲染路由以提高性能,这被称为静态渲染。因此,如果您的数据发生更改,在视图上并不会响应更改


### 静态和动态渲染


目前dashboard是静态的,并没有实时数据更新


**静态渲染**


1. 更快的网站 - 预渲染的内容可以缓存并在全球范围内分发。这确保了世界各地的用户可以更快、更可靠地访问您网站的内容。
2. 减少服务器负载 - 由于内容已缓存,因此服务器不必为每个用户请求动态生成内容。
3. SEO - 搜索引擎爬虫更容易对预渲染的内容进行索引,因为内容在页面加载时已经可用。这可以提高搜索引擎排名。


**动态渲染**


1. 实时数据 - 动态呈现允许应用程序显示实时或经常更新的数据。这非常适合数据经常更改的应用程序。
2. 特定于用户的内容 - 更轻松地提供个性化内容(如仪表板或用户配置文件),并根据用户交互更新数据。
3. 请求时间信息 - 动态呈现允许您访问只能在请求时知道的信息,例如 Cookie 或 URL 搜索参数。


在/app/lib/data.ts 文件中使用unstable\_noStore,并将注释解开(测速,人工阻塞)  
 [Segment Config Option]( )



/**
* 使用在服务器组件或数据获取函数中调用 unstable_noStore 的 Next.js API 来选择退出静态渲染
* 注意: unstable_noStore 是一个实验性 API,将来可能会更改。
* 如果您希望在自己的项目中使用稳定的 API,也可以使用 Segment Config Option export const dynamic = “force-dynamic” 。
*/
import { unstable_noStore as noStore } from ‘next/cache’;
export async function fetchRevenue() {
// 此处添加 noStore() 以防止响应被缓存.
noStore();
try {
// Artificially delay a response for demo purposes.
// Don’t do this in production 😃
// 解开注释
console.log(‘Fetching revenue data…’);
await new Promise((resolve) => setTimeout(resolve, 3000));

const data = await sql<Revenue>`SELECT \* FROM revenue`;
// 解开注释
console.log('Data fetch completed after 3 seconds.');

return data.rows;

} catch (error) {
console.error(‘Database Error:’, error);
throw new Error(‘Failed to fetch revenue data.’);
}
}
// …


### Streaming( 流)


流式处理是一种数据传输技术,它允许您将路由分解为更小的“块”,并在它们准备就绪时逐步将它们从服务器流式传输到客户端。  
 通过流式传输,您可以防止缓慢的数据请求阻止您的整个页面。这允许用户查看页面的某些部分并与之交互,而无需等待加载所有数据后才能向用户显示任何 UI。


**实现流式处理**


1. 在页面级别,使用 loading.tsx 文件。
2. 对于特定组件,使用 `<Suspense>` .


1、在文件夹中 /app/dashboard ,创建一个名为 loading.tsx (特殊文件:页面加载时显示)



// 导入骨架屏ui
import DashboardSkeleton from ‘@/app/ui/skeletons’;

export default function Loading() {
return ;
}


2、由于 `<SideNav>` 是静态的,因此会立即显示。用户可以在加载动态内容时与之 交互。  
 3、用户不必等待页面完成加载后再导航(这称为可中断导航)。


注意:loading.tsx 级别高于 /invoices/page.tsx 和 /customers/page.tsx页面,所以loading.tsx 也应用在了/invoices/page.tsx 和 /customers/page.tsx页面中。


解决:  
 使用路由组来更改此设置,在/app/dashboard下创建文件夹/(overview) ,将/app/dashboard/page.tsx和/app/dashboard/loading.tsx移入新文件中。



> 
> 路由组允许您将文件组织到逻辑组中,而不会影响 URL 路径结构。使用括号创建新文件夹时 () ,该名称不会包含在 URL 路径中。所以 /dashboard/(overview)/page.tsx 变成了 /dashboard .  
>  `-----------------`  
>  在这里,你使用路由组来确保 loading.tsx 仅适用于仪表板概述页面。但是,您也可以使用路由组将应用程序分成多个部分(例如路由 (marketing) 和 (shop) 路由),或者对于较大的应用程序按团队分隔。
> 
> 
> 


4、Suspense 允许您延迟渲染应用程序的某些部分,直到满足某些条件(例如加载数据)。您可以将动态组件包装在 Suspense 中。然后,向它传递一个回退组件,以便在动态组件加载时显示。


如果您还记得缓慢的数据请求, fetchRevenue() 则这是减慢整个页面速度的请求。您可以使用 Suspense 仅流式传输此组件并立即显示页面 UI 的其余部分,而不是阻止您的页面。


在 /dashboard/(overview)/page.tsx 删除所有 fetchRevenue() 实例及其数据,并导入Suspense、RevenueChartSkeleton



// 移除fetchRevenue
import { fetchLatestInvoices, fetchCardData } from ‘@/app/lib/data’;
// 导入Suspense ,RevenueChartSkeleton
import { Suspense } from ‘react’;
import { RevenueChartSkeleton } from ‘@/app/ui/skeletons’;

// const revenue = await fetchRevenue(); 删除
// 修改
<Suspense fallback={}>


修改/app/ui/dashboard/revenue-chart.tsx文件



import { fetchRevenue } from ‘@/app/lib/data’;
export default async function RevenueChart() { // 移除参数
const revenue = await fetchRevenue(); // 获取数据
// …
return (
// …
);
}


练习


将card组件包裹在`Suspense`中,一个一个加载时会出现popping effect,可能会造成视觉上的不和谐。  
 解决:  
 1、在/app/dashboard/page.tsx删除card相关的实例及其数据,导入CardsSkeleton 、CardWrapper



// 修改(添加CardsSkeleton )
import { RevenueChartSkeleton,LatestInvoicesSkeleton,CardsSkeleton } from ‘@/app/ui/skeletons’;
// 导入CardWrapper 组件
import CardWrapper from ‘@/app/ui/dashboard/cards’;
// 删掉
// const {totalPaidInvoices,totalPendingInvoices,numberOfInvoices,numberOfCustomers} = await fetchCardData()
{/*


*/}
// 修改成
<Suspense fallback={}>


2、在/app/ui/dashboard/cards.tsx文件中获取数据,将card注释去掉



// …
import { fetchCardData } from ‘@/app/lib/data’;

// …

export default async function CardWrapper() {
const {
numberOfInvoices,
numberOfCustomers,
totalPaidInvoices,
totalPendingInvoices,
} = await fetchCardData();

return (
<>




</>
);
}


3、刷新页面,您应该会看到所有卡同时加载。当您希望同时加载多个组件时,可以使用此模式。


### 搜索与分页


#### 总结一下

面试前要精心做好准备,简历上写的知识点和原理都需要准备好,项目上多想想难点和亮点,这是面试时能和别人不一样的地方。

还有就是表现出自己的谦虚好学,以及对于未来持续进阶的规划,企业招人更偏爱稳定的人。



万事开头难,但是程序员这一条路坚持几年后发展空间还是非常大的,一切重在坚持。



为了帮助大家更好更高效的准备面试,特别整理了《前端工程师面试手册》电子稿文件。

![](https://img-blog.csdnimg.cn/img_convert/621960a57eb42479e02d6d64c0c81891.png)



![](https://img-blog.csdnimg.cn/img_convert/5230c48fd0fcb265f3401a21603bda2b.png)



**前端面试题汇总**

![](https://img-blog.csdnimg.cn/img_convert/42728594459506983a38ca2b86545fc6.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)**
![img](https://img-blog.csdnimg.cn/img_convert/52782cd8de139e6020e55051e71740f1.png)

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**


#### 总结一下

面试前要精心做好准备,简历上写的知识点和原理都需要准备好,项目上多想想难点和亮点,这是面试时能和别人不一样的地方。

还有就是表现出自己的谦虚好学,以及对于未来持续进阶的规划,企业招人更偏爱稳定的人。



万事开头难,但是程序员这一条路坚持几年后发展空间还是非常大的,一切重在坚持。



为了帮助大家更好更高效的准备面试,特别整理了《前端工程师面试手册》电子稿文件。

![](https://img-blog.csdnimg.cn/img_convert/621960a57eb42479e02d6d64c0c81891.png)



![](https://img-blog.csdnimg.cn/img_convert/5230c48fd0fcb265f3401a21603bda2b.png)



**前端面试题汇总**

![](https://img-blog.csdnimg.cn/img_convert/42728594459506983a38ca2b86545fc6.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)**
[外链图片转存中...(img-ky9lVzGW-1713326992669)]

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
  • 13
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值