==了解== 熟悉 掌握 精通
初始化
假设已安装,安装见 配置开发环境及项目管理
要先确保有node.js噢:node -v
然后 ———— 本来默认的手脚架是create-react-app,但是现在官方竟然不支持不维护了。于是又评测了一轮,现有两种,next和vite。next支持前端和后端,vite只搭前端,比较轻量。此项目使用next,因此记录基本上基于next,但同时有vite项目开发,零碎记一下。
此外有个基本知识,我竟不知。node中,如果安装代码带了-g,就是全局安装。否则,==在哪个文件夹下运行安装包代码,这个包就只会安在这个文件夹下面。==
使用create—react—app搭建
初始化一个新项目:npx create-react-app <项目名字>
进入项目,打开本地预览:npm start
或者yarn start
,yarn
比较好。
💡 现在又有了个pnpm
,我换一下
# 删除yarn
sudo npm uninstall -g yarn
# 安装pnpm
sudo npm install -g pnpm
#(在已经有yarn.lock的情况下)导入到pnpm
pnpm import
# 然后要build
pnpm run build
# 然后再start
pnpm start
💡 在build过程中会有不少错误,因为pnpm格式好像更严谨。改到没错就可以start了。
pnpm 有两种,pnpm install和pnpm add
如果想要将安装的包信息添加到 package.json 文件中,建议使用 pnpm add;
如果只是想简单地安装依赖包,可以使用 pnpm install。
目录结构:
react-project/
├── node_modules/ # 如果用npm,yarn就会有此项,包含了项目所需的所有Node.js模块。
├── public/ # 包含了在项目中公开可访问的文件。
│ ├── favicon.ico
│ ├── index.html # 入口页面。一般是整个html最外的框架,有<head>和<body>
│ ├── manifest.json # 配置文件。提供app相关的信息,如名称、作者、图标及描述等。
│ └── robots.txt
├── src/ # 包含了项目的源代码。
│ ├── App.js # react应用的根组件,最高层级是<App />
│ ├── index.js # 所有node应用传统的入口点。它渲染App.js
│ ├── index.css # 这是应用的主要样式表。
│ └── App.test.js:这是用于测试App组件的测试文件。
├── ...
├── yarn.lock # 后面换pnpm的时候就换成pnpm.lock
└── package.json # 包含了项目的基本信息,如项目的目的、如何安装和运行项目等。
使用vite搭建
初始化
# 注意这里最后如果是--template react,不带ts,就会是js
pnpm create vite [项目名字] --template react-ts
cd [项目名字]
pnpm i
pnpm run dev
然后地址是:http://localhost:5173/
安装tailwind CSS
-
安装
pnpm add -D tailwindcss postcss autoprefixer
-
生成
tailwind.config.js
和postcss.config.js
npx tailwindcss init -p
-
因为是ts项目,所以要改掉js,但是要改成’.cjs'
-
在
tailwind.config.js
中的content部分添加
content: [
'./src/**/*.{js,jsx,ts,tsx}', // 如果项目中的JavaScript或TypeScript文件使用了Tailwind CSS类名
'./index.html', // 如果项目中的HTML文件使用了Tailwind CSS类名
// 可根据项目结构添加更多的路径
],
- 把
vite.config.ts
添加成为
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from "tailwindcss"
import autoprefixer from "autoprefixer"
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
css: {
postcss: {
plugins: [
tailwindcss,
autoprefixer,
]
}
}
})
- 在
./src/index.css
文件中添加:
@tailwind base;
@tailwind components;
@tailwind utilities;
这里会有一个小警告:Unknown at rule @tailwind
解决方法:在vscode的extensions图标点开,搜索找到PostCSS Language Support
,并安装。
安装其他包
# 一个react规范
pnpm add -D eslint eslint-config-react-app
touch .eslintrc.cjs
# 对import 进行自动排序插件
pnpm add -D prettier eslint-config-prettier prettier-plugin-organize-imports prettier-plugin-tailwindcss
touch .prettierrc.cjs
.eslintrc.cjs里添加
module.exports = {
extends: ['react-app', 'prettier'],
};
.prettierrc.cjs里添加
module.exports = {
singleQuote: true,
plugins: ['prettier-plugin-organize-imports', 'prettier-plugin-tailwindcss'],
organizeImportsSkipDestructiveCodeActions: true,
};
pre配置
在tsconfig.json里添加
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
},
}
vite.config.ts变成
import path from "path"
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
})
js手动迁移到ts
如果安装了默认的js,想事后再迁移就要手动
- 迁移到ts
- 安装(💡在项目的根目录下!)
pnpm install -D typescript @types/react @types/react-dom
- 将所有
.jsx
扩展名改为.tsx
- 在
main.tsx
中,有一行ReactDOM.createRoot(document.getElementById('root')).render(...)
加一个as HTMLElement
变成
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(...)
index.html
中,有一行src="/src/main.jsx"
,改成main.tsx
vite.config.js
文件的扩展名改为.ts
。- 创建三个文件:
// src/vite-env.d.ts
/// <reference types="vite/client" />
// tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
// tsconfig.node.json
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"strict": true
},
"include": ["vite.config.ts"]
}
都安装好之后项目的目录就是:
react-project/
├── public/ # 此文件夹不会被构建工具打包,一般用来放网站的图标或者全局配置文件。
│ └── vite.svg
├── src/ # 包含了项目的源代码。
│ ├── assets/ # 放静态资源,图片字体等。
│ │ └── vite.svg
│ ├── App.css
│ ├── App.tsx # 主组件。通常包含应用的布局和路由。
│ ├── main.tsx # 项目主入口,负责渲染App组件。
│ ├── index.css # 这是应用的主要样式表。可以改为main.css
│ ├── vite-env.d.ts # ts声明文件
│ ├── components/ # 组件目录。自己加的
│ ├── router/ # 自己加的,可放路由
│ ├── lib/ # 自己加的,可放外部/自己写的依赖库,比如jar
│ └── utils/ # 自己加的,可存放常用函数的封装。
├── eslinttrc.cjs # 检查代码质量
├── index.html
├── postcss.config.cjs # tailwind CSS的相关配置.PostCSS不支持es6语法,要用commonjs
├── tailwind.config.ts # tailwind CSS的配置
├── tsconfig.json # ts相关配置
├── tsconfig.node.json # ts相关配置
├── vite.config.ts # vite配置,配置服务器端口ip,项目打包构建之类
├── pnpm-lock.yaml
└── package.json # 项目基本配置,可设置项目的目的、如何安装和运行项目等。
使用next.js搭建
初始化项目:
# ----------
npx create-next-app@latest <项目名字>
# 进入该文件夹
npm i # npm install, 安装package.json列出的依赖包,并将它们安装到node_modules文件夹中。
npm run dev # 启动开发服务器
# ---------- 如果是用pnpm
pnpm create react-app <项目名字>
# 进入该文件夹
pnpm install
pnpm start
pnpm dev
和pnpm run build
的区别:
前者用于开发和测试,后者用于创建生产环境下的应用程序。运行完pnpm run build
要运行pnpm start
(比如说我pnpm dev
正常运行fetch('/api/posts')
,但是run build
里就不行,必须加完全部绝对路径。)
命令的流程:
- 开发阶段:使用pnpm dev来启动开发服务器,进行开发和测试。
- 构建阶段:使用pnpm run build来创建优化的生产构建。(通常在package.json中配置为next build)
- 运行阶段:使用pnpm start来启动生产服务器,为用户提供服务。(通常在package.json中配置为next start)
目录结构:
react-project/
├── .next/ # next.js的缓存目录。如果用pnpm就没有node_module了
├── public/ # 放静态资源
├── src/ # 这个安装的时候可以选择是否创建src,我想有src结构比较清晰,因为comp可以放进去,app里就都放路由。
│ ├── app/
│ │ ├── about/
│ │ │ └── page.tsx # 在app路由模式下,只要是'page'就当成路由,名字为上级文件夹名。所以这个页面的内容的地址就是localhost:30000/about
│ │ ├── archive/
│ │ │ ├── page.tsx # 同about。这个文件夹还可放别的,比如css等。
│ │ │ └── index.css
│ │ ├── page.tsx # app路由模式,且在app/根目录下,此页面内容就是home页。
│ │ ├── layout.tsx # 根布局文件,有<head>和<body>及其他全局共享标签。因为包含全局元数据,所以metadata在这里定义。
│ │ ├── template.tsx # 根模板文件。
│ │ ├── loading.tsx # 定义加载界面
│ │ ├── error.tsx # 定义错误处理
│ │ ├── not-found.tsx # 定义 404 页面
│ │ ├── globals.css # 全局的样式
│ │ └── favicon.ico
│ ├── components/ # 非页面级的共用组件,可在多个页面重复用。比如side,nav模块。因为app里都放的是路由文件夹,所以这个挪出来。
│ │ ├── sidebar/
│ │ │ ├── index.tsx # 就放sidebar的内容。tip是import到别的页面时index可以不用写。
│ │ │ └── index.css # 也可以加样式
│ │ ├── MDX/ # 说一下此文件夹意思是解析markdown文件到html
│ │ │ └──index.tsx # 同sidebar。
│ │ └── ...
├── ...
├── page/ # 放页面级组件。这个文件夹我生成的时候是没有的,但gpt告诉我有,用做路由相关,暂且放在这。
├── tailwind.config.ts #这是Tailwind CSS的配置文件
└── package.json # 标准的npm配置文件,包含了项目名称、版本、描述、作者等信息,以及项目的依赖包。
app路由模式注意的点:
-
pages 文件夹。它是 Next.js 中的一个特殊目录。在这里创建的每个文件都会成为一个自动路由的页面。like
pages/
├── index.js:博客首页
├── about.js:关于页面
├── blog/[slug].js:动态路由,用于显示博客文章 -
app/文件夹下的每个子文件夹内,也都可有一套 page.tsx、layout.tsx、error.tsx等,它们的功能一样,只是作用范围就是本文件夹。那么在根目录下的这些文件,就都是根xx文件。
-
layout 和 template
都能用來让子路由共享 components,区别在于状态的保持。切换路由时,layout 不会 re-render,而 template 会 re-render。
比如从home标签换到about(假设它俩共享布局页面),之前在输入框输入的文字,如果是layout就不会消失,template就会消失。
原理是,template会在导航的时候为每个子级创建一个新实例。这就意味着当用户在共享一个template的路由间导航时,将挂载组件的新实例,DOM 元素会重新创建,所以状态不会保留。
template常用在:
如果需要在导航(路由切换)的时候做一些事情如发送统计代码、重新加载、添加动画效果等等时使用 template.js
useSelectedLayoutSegment
升级js 和 css
js → tsx
在配置next.js时自动就生效了。所以还要研究一下这块怎么手动操作。
css → scss
yarn add sass
或 npm install sass
💡 要在react根目录下安装,不要在全局安装
一些包
shadcn单独添加组件:
npx shadcn-ui@latest add
然后它就会让你选
—————— ❗️ 接下来除非指明,记录均基于next.js
版的react ——————
概念填坑
- global.css的作用域是什么?如何调用?
-
在global.css中定义的组件、参数等等,被导入layout.tsx之后,可以不用显式调用标签,而自动应用。
同时,其他地方css文件里面也可以自由使用在这里定义的参数。 -
react中,一个组件必须返回一个单一的根节点。如果需要返回多个元素,但又不想添加额外的DOM元素,可以使用Fragment。Fragment是一对空标签<></>,就加在最外层。
-
什么是组件?
在前端中(后端也有组件),实现一个页面上的功能,就是一个组件,比如一个按钮,一组导航栏。形式就是以一个自定义的标签出现的,比如自己定义了<mySidebar>
,这个就是一个组件。
怎么实现呢?通常就是const mySidebar = () => { // 一些处理 return (<></>)}
这样定义一个函数,返回一组标签,就完成了一个组件。 -
包裹类型的双标签和不用包裹的单标签怎么定义呢?
单标签的,学名称为自闭合,比如<Header />
。
双标签的,叫成对闭合,比如<RootLayout></RootLayout>
。
这两个创建的区别是,函数定义时参数放在哪。
如果没带参数,就只能使用单标签样式。
// 定义
function Header() {
return <header>这是头部</header>;
}
// 使用
<Header />
如果带参数,且定义组件时return部分,参数写在元标签<>内部,那么使用该组件时,就也要在<标签 >内部带参。
// 定义
function Header({ class }) {
return <div className = {class}> </div>;
}
// 使用
<Header class="flex"/>
如果带参数,且定义组件时return部分,参数写在两标签<></>之间,那么使用该组件时,也写在<></>之间
// 定义
function Header({ a }) {
return <div>{a}</div>;
}
// 使用
<Header>{"我的标题"}<Header/>
相应的,如果定义组件时带多个参数,位置也和使用该组件要一一对应。就不举例子了。
💡 当有多层级带参数的标签时,children会自动继承。
-
怎么有两种函数定义的形式?区别是啥?
定义函数式组件时,有两种不同的定义方式。
命名函数式组件function Header({ pro }) { return() }
和 匿名函数式组件const Header = ({ pro }) => { return() }
,也称为箭头函数组件。
功能上没啥区别,但是箭头式更简便,一般更经常用这个。 -
import时
@
是啥东西
就是简写,alias的部分路径。
先在设置中,定义映射关系。比如在tsconfig.json
(或jsconfig.json
)中映射"paths": {"@/*": ["./*"]}
,就是将@
开始的所有路径,映射到当前【相对于tsconfig.json
来说的当前】./
下所有路径。
引用的时候,比如import Header from '@/components/Header'
,意思就相当于fromreact—project/components/Header
。
但是我都会映射一个{"@/*": ["/src/*"]}
-
路由是什么
在react中,Link
标签可以用于项目中页面互相跳转,a
标签可以用于站外链接。相应地,href用于传统的全页面刷新的链接,而to用于React单页应用中的客户端路由。
用的时候:<Link to="/achieve">ACHIEVE</Link>
==以上都基于react。==
如果用next引入Link,则此Link应该搭配href。
next.js
的路由引入:import Link from 'next/link'
- 都控制路由,
next/link
和next/router
、next/navigation
有什么区别?
首先,next/navigation
是next/router
的增强, Next.js 13 中新增的模块。
next/link
和上面两个的区别是,(import from next/Link)是直接直挺挺的跳转路由,进行客户端导航,创建静态链接。
而后两者,用于编程式导航,在 JavaScript 代码中实现页面之间的跳转。意思就是,如果跳转链接时,需要一些条件,比如提交表单并跳转,按条件导航(登录导到A,未登录导到B,等固定时间导航),或者处理错误/特殊情况,这些时候就需要用编程式导航,动态控制跳转。
比如,
import { usePathname } from 'next/navigation';
import Link from 'next/link';
const pathname = usePathname();
// ...
return (
<Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
Home
</ Link>
)
这段代码,导航至首页,添加了条件,如果当前链接是首页,就增添一个active
标签,控制样式就更灵活了。
-
客户端和服务端怎么分,怎么还分哪端渲染?我怎么知道哪端渲染……
nextjs 13 所有组件均默认为服务端组件,如果需要使用客户端组件在最顶部增加 “use client” 标识
在服务端组件可直接使用 async/await 来进行异步数据的获取 -
ts里加类型都怎么加,语法是什么。
其他组件设置和定义
Tailwind CSS
@layer 指定样式,并注入到css文件的指定部分。
我理解使用这个包裹 {body{}, .class{}}等等,可以手动设定优先级。
@layer reset, defaults, patterns, components, utilities, overrides;
从左到右,优先级递增。每个样式,覆盖它左边的样式,被它右边覆盖。
一般情况下,样式定义的内容like:
base:这个层通常包含重置规则或应用于普通 HTML 元素的默认样式。比如可以在这个层中定义 h1 和 h2 的默认字体大小。
components:用于类基础的样式。比如定义.btn-blue
utilities:这个层包含小的、单一目的的类,这些类应该始终优先于任何其他样式。比如定义 .filter-none 和 .filter-grayscale 这两个类的样式。
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
h1 {
@apply text-2xl;
}
h2 {
@apply text-xl;
}
}
@layer components {
.btn-blue {
@apply bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded;
}
}
@layer utilities {
.filter-none {
filter: none;
}
.filter-grayscale {
filter: grayscale(100%);
}
}