Nextjs使用教程

一.手动创建项目

建议看这个中文网站文档,这个里面的案例配置都是手动的,也可以往下看我这个博客一步步操作
1.在目录下执行下面命令,初始化package.json文件

npm init -y

2.安装react相关包以及next包

yarn add next react react-dom
// 或者
npm install --save next react react-dom

3.在package.json文件的script节点,新增以下内容

  "scripts": {
    ...,
    "dev": "next",  // 开发时运行
    "build": "next build", // 打包时运行
    "start": "next start"  // 打完包启动服务的命令
  }

注意:Next.js 只支持React 16及以上

4.根目录下新建pages目录(这里面就是所有页面代码了,会根据这个目录的内容自动生成路由)

5.在pages里面新建index.js,放入以下内容进行测试

export default function(){
    return <div>我是pages/index下面的内容</div>
}

6.启动项目测试

npm run dev
// 或者
yarn run dev

7.访问控制台的local地址,显示出如下页面

在这里插入图片描述
8.打包

npm run build
// 或者
yarn run build

打完包会在项目下新建生成一个.next文件,在根目录下执行如下命令会和开发时看到的效果一致

npm run start
// 或者
yarn run start

二.快速创建项目

官网文档

执行下面创建项目的命令

npx create-next-app next-create

下面会出现一堆询问的配置信息,这里直接走默认就好了

定义路由

这里的页面都是统一放到app文件夹下面每个文件的page.js文件

例如直接访问localhost:3000则访问的是app/page.js文件

例如直接访问localhost:3000/user则访问的是app/user/page.js文件

export default function(){
    // className={"text-red-500"} 使用原子化css标签
    return <div className={"text-red-500"}>我是user/page文件</div>
}

如果访问的页面有很多网格效果,则去app/globals.css里面把样式都删除,只留前三行即可

页面与布局

将app/Layout.js进行改造

import { Inter } from "next/font/google";
import "./globals.css";

const inter = Inter({ subsets: ["latin"] });

export const metadata = {
  title: "Create Next App",  // 网站标题
  description: "Generated by create next app", // 描述信息
};

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={inter.className}>
        app下面的layout
        {children}</body>
    </html>
  );
}

新建app/user/Layout.js存入以下内容

export default function userLayout({ children }) {
  return (
    <section>
        user下面的layout
        {children}
    </section>
  );
}

访问localhost:3000

在这里插入图片描述
访问localhost:3000/user

在这里插入图片描述
通过对比可以发现,app下面的就是公共的根样式,下面每个Layout.js都会继承到,然后每个文件夹下都可以定义当前路由页面的样式

链接和导航

修改下app/page.js内容如下

'use client';
import Link from "next/link";
import { useRouter } from "next/navigation";


export default function Home() {
  const router = useRouter()
  return (
    <>
    <h1 className="text-4xl text-orange-600">Hello Name</h1>
    <br></br>
    <Link href={"/user"}>跳转到user路由</Link>
    <br></br>
    <button onClick={()=>{router.push('/user')}}>点击跳转/user</button>
    </>
  );
}

滚动到新路由的指定位置处,相当于锚点链接

<Link href="/dashboard#settings">Settings</Link>
 
// Output
<a href="/dashboard#settings">Settings</a>

路由组

项目下新建三个路径文件

  • app/(marketing)/about/page.js
  • app/(marketing)/bolg/page.js
  • app/(marketing)/(shop)/acconut/page.js

在每个page.js里面随便写点内容,访问以下路径

  • localhost:3000/about
  • localhost:3000/bolg
  • localhost:3000/account

可以发现都能被访问到,总结规律就是文件夹名字带括号的相当于可以忽略了

路由组不参与url的设定的

个人感觉唯一作用是用于设置共同的Layout.js

创建如下两个Layout.js文件

  • app/(marketing)/Layout.js
  • app/(marketing)/(shop)/Layout.js

在这两个里面添加如下代码

export default function userLayout({ children }) {
  return (
    <section>
        marketing下面的layout
        {children}
    </section>
  );
}
export default function userLayout({ children }) {
  return (
    <section>
        marketing下面shop的layout
        {children}
    </section>
  );
}

运行后会发现,marking的Layout,js被它里面所有文件所共用,shop里面的Layout.js被shop里面的文件所共用,因为这个案例shop在marking里面的,因此shop里面的文件也共用marking里面的样式,这就是路由组,按照上面传统的方式建路由,需要每个文件单独设置自己的Layout.js,使用路由组可以达到复用性

动态路由

在app/user新建[username]文件夹,里面的page.js文件内容如下

export default function({params}){
    console.log('params',params);
    return <>
    <div>我是user/[username]动态路由{params.username}</div>
    </>
}

将app/page.js内容修改如下

'use client';
import Link from "next/link";
import { useRouter } from "next/navigation";


export default function Home() {
  const router = useRouter()
  return (
    <>
    <h1 className="text-4xl text-orange-600">Hello Name</h1>
    <br></br>
    <Link href={"/user/王二"}>跳转到user路由</Link>
    <br></br>
    <button onClick={()=>{router.push('/user/王五')}}>点击跳转/user</button>
    </>
  );
}

当点击跳转到路由时,后面的参数就是动态参数,文件名username就是参数名,可以被params.username接收到并显示到页面上

上面有个弊端就是只支持一级动态参数,如果希望多级的话可以将[username]文件名换成[…username]这样就是可以匹配到后面所有参数,如下地址

  • localhost:3000/user/1/2/3/4/5

效果图

在这里插入图片描述
但是这里建议将[…username]文件名替换为[[…username]],两者区别在于[[…username]]当动态参数为空时也会被匹配到,剩余部分两者功能一致

Loadding加载和流的处理

1.在app下面新建Loading.js组件

export default function(){
    return <div className={"text-2xl text-pink-400"}>Loading...</div>
}

2.修改app/Layout.js

import { Inter } from "next/font/google";
import { Suspense } from "react";
import Loading from './loading';  // 引入app/loading.js
import "./globals.css";

const inter = Inter({ subsets: ["latin"] });

export const metadata = {
  title: "Create Next App",  // 网站标题
  description: "Generated by create next app", // 描述信息
};

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <Suspense fallback={<Loading></Loading>}> // 2.使用SusPense将页面包裹
        	app下面的layout
        	{children}
        </Suspense>
        </body>
    </html>
  );
}

子组件代码

这里使用了async/await模拟了一下异步,这是个细节,因为上面的loadding效果如果要出来的话,页面数据必须要是有异步效果,因为我没注意到这点,费了点时间才搞明白

export default async function Posts() {
  await new Promise((resolve) => setTimeout(resolve, 2000));
  return <div>1111</div>;
}

注意:将Lodding放到app/Layout.js里面包裹的话,则针对所有页面生效,如果某个页面有不一样的loading效果的话,则需要在当前文件夹里面的Layout.js去单独引入对应的Loading.js,可以在当前文件夹里面创建个Loading.js,这样的话Loading.js的样式仅仅作用于当前文件夹下的所有页面

import { Suspense } from "react";
export default function userLayout({ children }) {
  return (
    <section>
        // 这个loading效果仅作用于当前文件夹下面的所有页面
        <Suspense fallback={<div className={"text-2xl text-pink-400"}>Loading...</div>}>
        user下面的layout
        {children}
      </Suspense>
    </section>
  );
}

注意:必须是渲染的页面内有异步操作(如async/await)才会有Loading.js效果

错误处理

新建app/error.js,放入以下内容

'use client'

export default function({error,reset}){
    return (
        <div>
            <h2>我是全局的错误样式处理</h2>
            <button onClick={()=>reset()}>重试一下</button>
        </div>
    )
}

也可以对每个页面单独定义路由样式,只需要在目标页面的文件夹内新建error.js,放入以下内容即可

例如我在app/user/error.js内加入以下内容

'use client'

export default function({error,reset}){
    return (
        <div>
            <h2>app/user 页面内有错误啦!!!</h2>
            <button onClick={()=>reset()}>重试一下</button>
        </div>
    )
}

例如我们在目标的user页面加入一些错误信息

export default function Posts() {
  console.log('a',a);  // 这里没有a变量,因此这里会报错
  return <div>1111</div>;
}

当我们在浏览器访问localhost:3000/user就会报出以下错误

在这里插入图片描述
当我们访问其他页面有错误信息时,但是没有给那个页面单独定义错误样式,则会触发全局的错误样式

例如访问: localhost:3000/about

在这里插入图片描述

组件化渲染

并行路线,也就是web端的组件

在app下面新建@home和@setting文件夹,里面都新建一个page.js文件,在里面写一点页面

在app/Layout.js里面改为如下页面代码

import { Inter } from "next/font/google";
import { Suspense } from "react";
import Loading from './loading';
import "./globals.css";

const inter = Inter({ subsets: ["latin"] });

export const metadata = {
  title: "Create Next App",  // 网站标题
  description: "Generated by create next app", // 描述信息
};

export default function RootLayout({ children,home,setting }) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <Suspense fallback={<Loading></Loading>}>
        app下面的layout
        {home}
        {children}
        {setting}
        </Suspense>
        </body>
    </html>
  );
}

在这里插入图片描述

可以发现组件效果已经出来了

但是上面的仅限于在Layout.js里面使用的组件,下面是可以应用到我们页面里面的组件的案例

在app平级处创建components/frame/index.js,放入以下内容

import Image from "next/image";

export default function({photo}){
    console.log('photo',photo);
    return <>
    <Image src={photo.src} alt="" width={600} height={600} className={'w-full object-cover aspect-square col-span-2 w-28'}></Image>
    </>
}

在app里面新建photo/page.js文件,插入以下内容

import Photo from "@/components/frame"  // 引入组件
export default function(){
    const photo = {src:'https://take-saas.oss-cn-hangzhou.aliyuncs.com/wechat_applets/coach/bgcimg/bgc-13.png'}
    // 给组件传值
    return <Photo photo={photo}></Photo>
}

注意:这里可能会报错图片问题(网络图片需要加一下白名单才能正常加载,如下在next.config.mjs里面进行配置)

/** @type {import('next').NextConfig} */
const nextConfig = {
    images:{
        domains:['take-saas.oss-cn-hangzhou.aliyuncs.com'] // 这里是存放域名白名单处
    }
};

export default nextConfig;

然后就可以看到图片正常加载了

在这里插入图片描述

定义404页面

在app下面新建not-found.js,放入以下内容

export default function(){
    return <div className={"text-2xl text-pink-400"}>访问页面不存在...</div>
}

当页面访问一个不存在的页面路由时,页面显示效果如下

在这里插入图片描述
PS:由于博客内容都是自学做的整理,在某一次排查问题时,也就是刚好博客写到这里时,刷到了一个博主的nextjs教程合集,也挺详细的,力推点击进入合集地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/679092.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

特步公主与七匹狼公子举行婚礼:“校服是你,婚纱也是你”!95后“二代”们开始接班?

从校服到婚纱&#xff0c;两位福建晋江系企业的“二代”上演了一出豪门青梅竹马的网络小说情节。 6月1日是个有意思的日子&#xff0c;有人庆祝儿童节&#xff0c;有人举办婚礼。 当天晚上&#xff0c;特步集团“小公主”丁佳敏在其社交媒体平台官宣了喜讯&#xff0c;并且晒…

重磅消息! Stable Diffusion 3将于6月12日开源 2B 版本的模型,文中附候补注册链接。

在OpenAI发布Sora后&#xff0c;Stability AI也发布了其最新的模型Stabled Diffusion3, 之前的文章中已经和大家介绍过&#xff0c;感兴趣的小伙伴可以点击以下链接阅读。Sora是音视频方向&#xff0c;Stabled Diffusion3是图像生成方向&#xff0c;那么两者没有必然的联系&…

Nginx在线部署和离线部署方式

Nginx 有两种安装方式: 1)在线安装的方式 1.添加Nginx 到yum源 sudo rpm -Uvh <http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm> 2.安装Nginx,直接使用yum方式 yum install -y nginx 3.启动nginx,刚安装的nginx不…

AI程序员来了,大批码农要失业

根据GitHub发布的《Octoverse 2021年度报告》&#xff0c;2021年中国有755万程序员&#xff0c;排名全球第二。 ChatGPT的出现&#xff0c;堪比在全球互联网行业点燃了一枚“核弹”&#xff0c;很多人都会担心“自己的工作会不会被AI取代”。 而2024年的AI进展速度如火箭般&am…

搭建chattts应用,做文字转语音

下载代码 git clone https://github.com/2noise/ChatTTS.git下载endpoint并上传&#xff1a; https://huggingface.co/2Noise/ChatTTS/tree/main 将上面下载的文件上传到服务器上 修改webui.py 更改为本地模型地址 import os import random import argparseimport torch i…

Java常规题技术分享

一、数组排序和添加成员 设计类Student和类StudentClass。 (1) 类Student有字符串属性name、double属性grade和int属性age 有带参数的构造方法&#xff0c;可设置三个属性的值 有各个属性的置取方法 (2)类StudentClass有Student数组属性stus存放班级成员&#xff0c;有int…

【ARM Cache 与 MMU 系列文章 7.6 -- ARMv8 MMU 相关寄存器介绍】

文章目录 MMU 转换控制寄存器 TCR_ELxTCR_ELx 概览TCR_ELx 寄存器字段详解TCR 使用示例Normal MemoryCacheableShareability MMU 内存属性寄存器 MAIR_ELx寄存器结构内存属性字段使用实例 MMU 地址翻译表基址寄存器 TTBR0/1_ELxTTBR0_ELx 寄存器概述寄存器结构功能和用途编程示…

【C++修行之道】类和对象(四)运算符重载

目录 一、 运算符重载 函数重载和运算符重载有什么关系&#xff1f; 二、.*运算符的作用 三、运算符重载的正常使用 四、重载成成员函数 五、赋值运算符重载 1.赋值运算符重载格式 传值返回和引用返回 有没有办法不生成拷贝&#xff1f; 2. 赋值运算符只能重载成类的…

思维导图-vb.net开发带进度条的复制文件夹功能c#复制文件夹

你们谁写代码会用流程图来做计划&#xff0c;或者写项目总结报告&#xff1f; .net带进度条复制文件夹 方案 列出所有子文件夹&#xff0c;再创建&#xff0c;复制文件 大文件可以单独做进度条 缺点&#xff1a;设计会更复杂 直接…

让你的博客实现负载均衡

零、缘起 有时候博客突然挂了&#xff0c;发现服务器厂商出了问题&#xff0c;很忧伤&#xff0c;我正在写着或查阅自家博客那种不可xx的内容。这时想着&#xff0c;如果这个博客有负载均衡就好了&#xff0c;空了想着实现下。 一分钟了解负载均衡的一切 选择第二种【反向代…

衡量网络性能的指标

带宽 测速&#xff0c;下载速度一般是MB&#xff0c;运营商用的是b&#xff0c;之间有差别&#xff0c;100M带宽就是100M b 100个人访问同一个服务器&#xff0c;那么这个服务器的并发连接数就是100&#xff0c;有上限&#xff0c;受到性能的限制&#xff0c;当前面连接好多了…

【数据结构与算法 经典例题】链表的回文结构(图文详解)

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《数据结构与算法 经典例题》C语言 期待您的关注 ​ 目录 一、问题描述 二、解题思路 三、C语言代码实现 一、问题描述 二、解…

链表反转--理解链表指针的基本操作

链表反转--理解链表指针的基本操作 链表反转的方法--主要是理解链表指针链表心得类节点是对象和指针区别&#xff1a; 链表反转的方法–主要是理解链表指针 根据值创建新列表 用一个链表指针代替整个新链表 两个链表的赋值 递归求解反向链表 用一个链表代替前后链表数…

解决使用gets(getchar)函数无法输入字符(字符串)和scanf_s函数显示缺少“scanf_s”整型参数的问题

一.函数介绍 gets函数&#xff1a; 该函数就是读取字符串&#xff0c;遇到空格不会停止&#xff0c;直到遇到换行字符&#xff0c;但是也会读取最后的换行字符&#xff08;这也就是我在写代码的时候遇到的一个问题&#xff09; getchar函数&#xff1a; 和gets函数类似&#x…

初识JAVA中的包装类,时间复杂度及空间复杂度

目录&#xff1a; 一.包装类 二.时间复杂度 三.空间复杂度 一.包装类&#xff1a; 在Java中&#xff0c;由于基本类型不是继承自Object&#xff0c;为了在泛型代码中可以支持基本类型&#xff0c;Java 给每个基本类型都对应了一个包装类型。 1 基本数据类型和对应的包装类 &am…

数字塔问题

#include<iostream> using namespace std; //从下向上得到最优值 void dtower(int a[][100],int s[][100],int n) {for(int in; i>1; i--){for(int j1; j<i; j){if(in)s[i][j]a[i][j];else{int ts[i1][j];if(t<s[i1][j1])ts[i1][j1];s[i][j]a[i][j]t;}}} } void…

MapReduce复习

一、MapReduce概述 1.定义 是分布式运算框架 MapReduce&#xff1a;用户处理业务相关代码自身的默认代码 2.优势劣势 优点&#xff1a; 1&#xff09;.易于编程。用户只关心业务逻辑&#xff0c;实现框架的接口。 2&#xff09;.良好的扩展性。可以动态增加服务器&#…

找不到steam_api64.dll,无法继续执行的原因及解决方法

电脑已经成为我们生活中不可或缺的一部分。然而&#xff0c;在使用电脑的过程中&#xff0c;我们经常会遇到一些常见的问题&#xff0c;其中之一就是找不到某个特定的动态链接库文件&#xff0c;比如steamapi64.dll。这个问题可能会导致某些应用程序无法正常运行&#xff0c;给…

通过DirectML和ONNXRuntime运行Phi-3模型

更多精彩内容&#xff0c;欢迎关注我的公众号“ONE生产力”&#xff01; 上篇我们讲到通过Intel Core Ultra系列处理器内置的NPU加速运行Phi-3模型&#xff0c;有朋友评论说他没有Intel处理器是否有什么办法加速Phi-3模型。通常&#xff0c;使用GPU特别是NVIDA的GPU加速AI模型…

LeetCode746使用最小花费爬楼梯

题目描述 给你一个整数数组 cost &#xff0c;其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用&#xff0c;即可选择向上爬一个或者两个台阶。你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。请你计算并返回达到楼梯顶部的最低花费。 解析 动态…