==了解== 熟悉 掌握 精通

初始化

假设已安装,安装见 配置开发环境及项目管理
要先确保有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 startyarn比较好。

💡 现在又有了个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

  1. 安装
    pnpm add -D tailwindcss postcss autoprefixer

  2. 生成tailwind.config.jspostcss.config.js
    npx tailwindcss init -p

  3. 因为是ts项目,所以要改掉js,但是要改成’.cjs'

  4. tailwind.config.js中的content部分添加

content: [
  './src/**/*.{js,jsx,ts,tsx}', // 如果项目中的JavaScript或TypeScript文件使用了Tailwind CSS类名
  './index.html', // 如果项目中的HTML文件使用了Tailwind CSS类名
  // 可根据项目结构添加更多的路径
],
  1. 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,
      ]
    }
  }
})
  1. ./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
  1. 安装(💡在项目的根目录下!)
    pnpm install -D typescript @types/react @types/react-dom
  2. 将所有.jsx扩展名改为.tsx
  3. main.tsx中,有一行ReactDOM.createRoot(document.getElementById('root')).render(...)
    加一个 as HTMLElement变成
    ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(...)
  4. index.html中,有一行src="/src/main.jsx",改成main.tsx
  5. vite.config.js文件的扩展名改为.ts
  6. 创建三个文件:
// 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 devpnpm run build的区别:
前者用于开发和测试,后者用于创建生产环境下的应用程序。运行完pnpm run build要运行pnpm start
(比如说我pnpm dev正常运行fetch('/api/posts'),但是run build里就不行,必须加完全部绝对路径。)

命令的流程:

  1. 开发阶段:使用pnpm dev来启动开发服务器,进行开发和测试。
  2. 构建阶段:使用pnpm run build来创建优化的生产构建。(通常在package.json中配置为next build)
  3. 运行阶段:使用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路由模式注意的点:

  1. pages 文件夹。它是 Next.js 中的一个特殊目录。在这里创建的每个文件都会成为一个自动路由的页面。like
    pages/
    ├── index.js:博客首页
    ├── about.js:关于页面
    ├── blog/[slug].js:动态路由,用于显示博客文章

  2. app/文件夹下的每个子文件夹内,也都可有一套 page.tsx、layout.tsx、error.tsx等,它们的功能一样,只是作用范围就是本文件夹。那么在根目录下的这些文件,就都是根xx文件。

  3. 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 sassnpm install sass
💡 要在react根目录下安装,不要在全局安装

一些包

shadcn单独添加组件:
npx shadcn-ui@latest add
然后它就会让你选

—————— ❗️ 接下来除非指明,记录均基于next.js版的react ——————

概念填坑

  1. global.css的作用域是什么?如何调用?
  • 在global.css中定义的组件、参数等等,被导入layout.tsx之后,可以不用显式调用标签,而自动应用。
    同时,其他地方css文件里面也可以自由使用在这里定义的参数。

  • react中,一个组件必须返回一个单一的根节点。如果需要返回多个元素,但又不想添加额外的DOM元素,可以使用Fragment。Fragment是一对空标签<></>,就加在最外层。

  1. 什么是组件?
    在前端中(后端也有组件),实现一个页面上的功能,就是一个组件,比如一个按钮,一组导航栏。形式就是以一个自定义的标签出现的,比如自己定义了<mySidebar>,这个就是一个组件。
    怎么实现呢?通常就是 const mySidebar = () => { // 一些处理 return (<></>)} 这样定义一个函数,返回一组标签,就完成了一个组件。

  2. 包裹类型的双标签和不用包裹的单标签怎么定义呢?
    单标签的,学名称为自闭合,比如<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会自动继承。

  1. 怎么有两种函数定义的形式?区别是啥?
    定义函数式组件时,有两种不同的定义方式。
    命名函数式组件function Header({ pro }) { return() } 和 匿名函数式组件const Header = ({ pro }) => { return() } ,也称为箭头函数组件。
    功能上没啥区别,但是箭头式更简便,一般更经常用这个。

  2. import时@是啥东西
    就是简写,alias的部分路径。
    先在设置中,定义映射关系。比如在tsconfig.json(或jsconfig.json)中映射"paths": {"@/*": ["./*"]},就是将@开始的所有路径,映射到当前【相对于tsconfig.json来说的当前】./下所有路径。
    引用的时候,比如import Header from '@/components/Header',意思就相当于from react—project/components/Header
    但是我都会映射一个{"@/*": ["/src/*"]}

  3. 路由是什么

在react中,Link标签可以用于项目中页面互相跳转,a标签可以用于站外链接。相应地,href用于传统的全页面刷新的链接,而to用于React单页应用中的客户端路由。
用的时候:<Link to="/achieve">ACHIEVE</Link>

==以上都基于react。==

如果用next引入Link,则此Link应该搭配href。
next.js 的路由引入:import Link from 'next/link'

  1. 都控制路由,next/linknext/routernext/navigation有什么区别?
    首先,next/navigationnext/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标签,控制样式就更灵活了。

  1. 客户端和服务端怎么分,怎么还分哪端渲染?我怎么知道哪端渲染……
    nextjs 13 所有组件均默认为服务端组件,如果需要使用客户端组件在最顶部增加 “use client” 标识
    在服务端组件可直接使用 async/await 来进行异步数据的获取

  2. 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%);
  }
}