组件是 React.js 的基础

next.js 默认使用 page.tsx 作为入口

1
2
/ -> app/page.tsx
/test -> app/test/page.tsx

React Hooks

useState 回调函数只有在第一次渲染的时候才会执行。

1
2
3
4
const [state, setState] = useState(() => {
const expensiveValue = computeExpensiveValue(); // 只会在首次渲染时执行
return expensiveValue;
});

父子组件的通信

请记住单向数据流。

  • 父组件 -> 子组件:通过 props 属性传递
  • 子组件 -> 父组件:通过 props 传递函数,触发父组件中的状态更新

在 vue 中父组件将 props 传递给子组件,子组件如果想要更改父组件中的值是通过抛出一个事件$emit通知父组件v-on来进行的。和原生 DOM 事件不一样,组件触发的事件没有冒泡机制。你只能监听直接子组件触发的事件。平级组件或是跨越多层嵌套的组件间通信,应使用一个外部的事件总线,或是使用一个全局状态管理方案。双向数据传递的方案可以使用 v-model

react hooks 类似 vue 组合式函数。

组件

类组件和函数式组件

按照组件的定义方式可以分为类组件和函数式组件。现在推荐使用函数式组件,代码写起来简洁,并且兼容类组件的所有特性,类组件是历史产物。

  • 纯函数:函数组件更容易编写纯函数(即相同的输入总是产生相同的输出,没有副作用)。
  • 不可变性:通过 Hooks(如 useState)管理状态时,状态更新是不可变的,这有助于避免副作用。
  • 组合性:函数组件可以更容易地组合和复用。

React Hooks 是 React 16.8 引入的革命性特性,它允许你在函数组件中使用状态(state)和其他 React 特性,而无需编写 class 组件。

客户端组件和服务端组件

组件默认是服务端组件,除非使用 use client。服务端组件是在服务器完成渲染的,不支持浏览器 API(window, document),不支持 React 状态和副作用。适合静态内容和数据密集型页面(在服务端组件完成数据库查询,不会被加载到客户端);而客户端组件适合强交互和需要浏览器 API 的页面。

server components 才能是 async 的

服务端组件是不是又回到了 JSP 时代?
服务端组件并不是简单地回到 JSP/PHP 的时代,而是在现代前端生态的基础上,结合了服务器端渲染的优势。它提供了以下改进: 组件化开发:基于 React 的组件化模式;性能优化:支持代码拆分、懒加载、边缘计算等现代性能优化技术。

构建工具

Vite:vue 作者开发,包含 2 部分:

  • 开发服务:服务于开发环境,ESM + HMR
  • 构建指令:服务于生产环境,用 Rollup 打包

Vite ESM打包器

传统打包工具例如 webpack 需要提供一个 entry,在启动的时候需要加载所有,而 ESM 打包器这种概念类似于按需加载,启动速度和更新速度都比较快。Vite 将模块区分为依赖和源码 2 类,提升开发服务启动时间。

依赖:开发时不会变动纯 js,Vite 会使用 esbuild 预构建(golang 编写)依赖。
源码:通常为 JSX,CSS,Vue SFC 等,经常会被编辑,需要转换,基于路由拆分。

Vite 以原生 ESM 方式提供源码,让浏览器接管打包工作。

Next.js

全栈框架 Next.js + Remix 已经占了 React 生态的 50%,官方的 create-react-app 已经很久没有进行维护了。主流的前端框架都有一个对应的全栈框架 meta framework。Vue + Nuxt, servlet + servletKit。前端的未来就是全栈。前端必须要用 js,SSR 框架必须使用 nodejs(php,java 无法实现)。

ServerAction

编写的函数是运行在服务端的,但是我们可以在客户端直接调用(就像调用本地函数一样),省去了在服务端对函数去包装 API 的这个过程。use server 标注的函数。

Router

Parallel Routies:@插槽,并行关系,例如:导航
Intercepting Routies: 在当前页面下打开其他页面的路由,但是不会跳离当前页面的上下文
Api Router Handler
Loading

文件路由

app 是应用根目录,app 目录下的每个目录代表一级路由

文件路由

上图中的 src/app/dashboard/app/[app] 最后的 [app] 表示动态路由(可以被变量替换)

layout 是可以被继承的,page 只有在当前对应的路由下才会生效。

Tailwind CSS

React 生态中一种常见样式的写法就是 Css in JS,最具有代表性的就是 stypled components,Emotion.js,Pandajs(几乎无运行时js),特性:灵活、模块化;缺点是性能(动态计算,插入节点),SSR 不友好(服务端渲染 html,需要在客户端进行样式合并,会有各种情况发生)

另一种解决方案是原子化 css,最小化样式文件(只有用到才会打包),随着项目复杂度的提升,最终用到的 css 文件的增量会越来越少。突出问题类名过长,难以阅读。

提供了一些语义化的实用的类名:bg-black/[.05] 的意思:

  • bg-black:这部分表示背景颜色为黑色
  • /:斜杠表示透明度(opacity)
  • [.05]:方括号是任意值语法,允许任何自定义值,.05 表示透明度 5%

冒号:有特殊的含义,用于表示修饰符。

  1. dark: 暗色模式
  2. hover: 鼠标悬停
  3. sm: 响应式断点,小屏幕
  4. focus: 聚焦
  5. active: 激活

hover:bg-red-500 鼠标悬停的时候变为标准红色。数值的取值是 50-950,较小的数值趋向于白色,较大的值趋向于黑色,一般 200 才开始有明显变化。

滤镜

基础滤镜

blur-{amount} - 模糊效果

1
2
3
blur-sm  /* 小模糊 */
blur /* 标准模糊 */
blur-lg /* 大模糊 */

brightness-{amount} - 亮度

1
2
3
brightness-50  /* 50%亮度 */
brightness-100 /* 正常亮度 */
brightness-200 /* 200%亮度 */

contrast-{amount} - 对比度

1
2
3
contrast-0    /* 无对比度 */
contrast-100 /* 正常对比度 */
contrast-200 /* 高对比度 */

颜色处理

grayscale - 灰度

1
2
grayscale-0  /* 原色 */
grayscale /* 完全灰度 */

sepia - 褐色

1
2
sepia-0  /* 原色 */
sepia /* 完全褐色 */

invert - 反转

1
2
invert-0  /* 原色 */
invert /* 完全反转 */

UI 组件

Shadcn = Radix UI + Tailwind Css 样式,无需进行安装,直接生成到项目中,作为源码的一部分。

最佳实践

  • key 可以帮助 React 识别列表中的每个元素,优化渲染性能,避免状态混乱。使用唯一标识符作为 key,避免使用索引。
  • 使用 uppy 进行文件上传。