当前位置: 首页 > news >正文

Vite+React+TypeScript+VsCode框架实战

引言

本文将开始React最新框架研究。

React 是由 Facebook(现 Meta)开发并于 2013 年开源的 JavaScript 库,专门用于构建用户界面,特别是单页应用程序(SPA)。React 允许开发者使用声明式的方式来构建可复用的 UI 组件。

React 的定位

  • 不是框架,而是库:React 专注于视图层(MVC 中的 V),不像 Angular 那样提供完整的框架解决方案
  • 组件化思想:将 UI 拆分成独立、可复用的组件
  • JavaScript 为中心:一切皆 JavaScript,包括结构、样式和逻辑

1 基本特点

主要归功于以下几个核心特点:

1.1 组件化

React 鼓励将整个用户界面拆分成一个个独立、可复用的小部件,即“组件”。每个组件管理自身的逻辑和状态,就像搭积木一样,通过组合这些组件来构建复杂的页面。

  • 可复用性:一个按钮、一个卡片都可以是组件,在应用的不同地方甚至不同项目中复用。
  • 可维护性:组件职责单一,修改某个功能时只需关注对应的组件,不影响其他部分。

1.2 声明式编程

使用 React,你只需要描述 UI “应该是什么样子”(即 UI 与数据状态的对应关系),而不用关心“如何一步步更新 UI”。当数据状态改变时,React 会自动高效地更新并渲染正确的组件。

  • 更直观:代码更简洁、更易读,让开发者专注于业务逻辑。
  • 更易调试:因为每个状态都对应一个明确的 UI 视图,使得追踪问题变得更容易。

1.3 虚拟 DOM

虚拟 DOM 是 React 高性能的关键。它是一个存在于内存中的、轻量级的真实 DOM 的 JavaScript 对象副本。

  1. 当组件状态发生变化时,React 会先在内存中创建一个新的虚拟 DOM 树。
  2. 然后,通过高效的Diffing 算法对比新旧虚拟 DOM 树的差异。
  3. 最后,只将变化的部分精确地更新到真实的 DOM 上。
    这种方式最大限度地减少了对真实 DOM 的直接操作(真实 DOM 操作非常消耗性能),从而实现了高效的渲染。

1.3 JSX 语法

JSX 是 JavaScript 的一种语法扩展,它允许你在 JavaScript 代码中直接编写类似 HTML 的标记。

  • 更直观:将 UI 结构和逻辑代码紧密结合在一起,使组件的结构一目了然。
  • 功能强大:JSX 最终会被编译成标准的 JavaScript 对象(React 元素),你可以在其中使用 JavaScript 的全部能力。

所以JSX是HTML和JavaScript杂交,主要用于 React 应用中。代码看起了自然不那么清爽,因为html的属性可能是js的关键子,所以一些属性发放到JSX中时需要改变名字,有点考记忆。

注释要写在大括号中,对大括号是情有独钟啊!

{/*注释...*/}

1.3.1 Vue 3 中的支持

虽然 Vue 最经典的用法是“模板语法”(Template Syntax,即 HTML 风格的写法),但 Vue 对 JSX 有着极好的支持,特别是在 Vue 3 中。

  • 使用场景:当你需要编写逻辑非常复杂的组件,或者需要利用 JavaScript 的全功能来处理渲染逻辑时,Vue 开发者往往会切换到 JSX/TSX。
  • 现状:Vue 3 的生态系统中,TSX(TypeScript + JSX)的使用非常普遍。Vue 官方甚至专门优化了对 JSX 的支持,移除了全局命名空间以避免与 React 冲突。

文件名从js->jsx->tsx 这种变化对代码规范和工程框架都影响很大。不过现在都关心代码是不是优雅了,加上AI生成,估计更没有人去管了。

这里提这个的原因时Vue组件文件以.vue结尾,和相当于JSX,如果按上面的说法直接改成JSX,不知到和react有啥区别了。真实情况时几乎没有人改,不是一个简单的rename那么简单,特别时大型项目。就像那些想用typescript,把.js改成改成.ts文件一样,哪有那么简单的事情,都是站起说话不腰疼的。这些演变其实兼容性都很差。你做几年了,发现有点项目用的时js,有的时ts,有的是tsx,其实是非常混乱的。一项技术都迭代得很快,所以要想做全栈再加上手机端,估计得天天加班学习。

如果你在vue中使用JSX,你得问问自己不直接用React理由是啥。

1.3.2 SolidJS

这是一个近年来非常火爆的高性能框架。

  • 特点:SolidJS默认就是使用 JSX 的。它的语法看起来和 React 的 JSX 几乎一模一样,但底层原理完全不同(SolidJS 没有虚拟 DOM,它是直接编译成原生 DOM 操作)。
  • 体验:如果你习惯了 React 的 JSX 写法,上手 SolidJS 会非常快,但能享受到更高的运行时性能。

这里就不得理解一下好奇的方式理解一下它为什么高性能了。vue,react本质上就是通过jssctipt动态生成和修改dom结构,自己在内存中维护了一份虚拟的dom树,如果状态变了,要生成新树,然后计算新树和老树差异,最后在dom上应用变更。这地方对比过程vue或者react做了优化,据说很高效。现在SolidJS来了,直接回归原始,没有虚拟dom,直接生成dom,傻眼了吧。虚拟dom的高性能一下被打脸了。这个机制其实就是类似原生dom的监听机制和局部刷新,只不过SolidJS 自动帮你做了。

因为一直做后端,所以长时间没有精力跟踪前端框架。所以一直好奇为啥虚拟Dom会比我局部刷新更快?局部刷新那个数据变了,我就刷哪里,虚拟dom怎么做到更快的?经常用到react或者vue写的页面,发现还没有以前jquery写的流畅。因为没有输入研究,也不知道式写的人没做好。还是框架的问题。

大道至简,最有效的方法通常都是最简单直白的。

1.4 单向数据流

在 React 中,数据通常是从父组件通过属性(props)单向地流向子组件。子组件不能直接修改父组件传来的数据,如果需要改变状态,必须通过父组件传递下来的回调函数来通知父组件进行更新。

  • 数据清晰:这种设计让数据流向变得清晰、可预测,便于理解和调试大型应用的状态。

1.5 钩子

Hooks 是 React 16.8 版本引入的一项革命性特性,它让你在不编写类组件的情况下,也能在函数组件中使用状态(state)和其他 React 特性(如生命周期)。

  • 简化组件:让函数组件成为主流,代码更简洁。
  • 逻辑复用:通过自定义 Hooks,可以非常方便地在不同组件间复用有状态逻辑,避免了类组件时代复杂的模式(如高阶组件、render props)。

1.6 丰富的生态系统与跨平台能力

React 本身专注于 UI 视图层,但拥有极其庞大和活跃的社区生态。

  • 灵活组合:你可以根据项目需求,自由选择并搭配路由(如 React Router)、状态管理(如 Redux, Zustand)等库。
  • 跨平台开发:基于 React 的核心思想,衍生出了React Native,让你可以用几乎相同的语法来开发原生的 iOS 和 Android 应用,实现“一次学习,随处编写”。

1.7 JSX与VUE模板风格对比

js是动态类型语言,其语言本身可读性就查。用jquery的年代,偶尔还会遇到动态添加html的场景,就会用js拼接html代码

html += '<div class="user-card ' + activeClass + '">import HelloWorld from './components/HelloWorld.jsx' function App() { const items = [ { id: 1, name: '苹果' }, { id: 2, name: '香蕉' }, ] {/*不用写引号和+号连接了,不然要疯,这注释要带一个大阔号!...*/} return ( <ul> {items.map((item) => ( <li key={item.id}> {item.name} </li> ))} </ul> ) } export default App

VUE

<template> <ul> <li v-for="item in items" :key="item.id"> {{ item.name }} </li> </ul> </template> <script setup> import { ref } from 'vue' import HelloWorld from './components/HelloWorld.vue' const items = ref([ { id: 1, name: '苹果' }, { id: 2, name: '香蕉' }, ]) </script>

其他的地方都一样,把关键地方放在一起来对比一下

return ( <ul> {items.map((item) => ( <li key={item.id}> {item.name} </li> ))} </ul> ) # 上面这个夹了几个括号,看起来有点蛋疼,欣赏不来这种艺术感 # 所以vue也支持JSX,不太懂 # 只喜欢干净直接一目录了然的代码 <template> <ul> <li v-for="item in items" :key="item.id"> {{ item.name }} </li> </ul> </template>

1.8 JSX组件名字

Reat要求组件首字母大写,以区别自定义组件的名字和原始html组件。实际上你会发现有很多HTML标签都是纯大写的。这个形同虚设,关于Vue组件命名规范也有类似问题。所有这种脚本感觉在规范性这方面做得都很差,工程化程度不友好。

2 基础框架搭建

项目架构都使用vite了,依赖管理使用pnpm ,如果不太了解的,可以看我前面的文章。

2.1 无ts

pnpm create vite@latest test-react-app1 -- --template react


2.2 有ts

pnpm create vite@latest my-react-app -- --template react-ts

创建的时候还自动给你跑起来了,不像vue需要你选组件。

2.3 导入

创建后用vs code导入项目就行了。

3 框架结构分析

3.1 无ts结构

我们先看看无生成的工程结构

3.1.1 index.html

<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>test-react-app1</title> </head> <body> <div id="root"></div> <script type="module" src="/src/main.jsx"></script> </body> </html>

入口文件,引入了main.jsx。<div id="root"></div>是渲染容器.这可以说是个模板文件,内容基本需要动。

3.1.2 main.jsx

import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' import './index.css' import App from './App.jsx' /* 将虚拟的dom渲染到html的root元素上 */ createRoot(document.getElementById('root')).render( /*(严格模式)是 React 提供的一个开发辅助工具*/ <StrictMode> /* 入口 */ <App /> </StrictMode>, )

导入了index.css全局样式文件和App.jsx组件,这个可以说是根组件,应用入口。这个也可以不用动,是个模板文件。

3.1.3 App.jsx

import { useState } from 'react' import reactLogo from './assets/react.svg' import viteLogo from '/vite.svg' import './App.css' /*应用的样式*/ /*返回了一个app组件*/ function App() { const [count, setCount] = useState(0) return ( <> <div> <a href="https://vite.dev" target="_blank"> <img src={viteLogo} className="logo" alt="Vite logo" /> </a> <a href="https://react.dev" target="_blank"> <img src={reactLogo} className="logo react" alt="React logo" /> </a> </div> <h1>Vite + React</h1> <div className="card"> <button onClick={() => setCount((count) => count + 1)}> count is {count} </button> <p> Edit <code>src/App.jsx</code> and save to test HMR </p> </div> <p className="read-the-docs"> Click on the Vite and React logos to learn more </p> </> ) } export default App

这个就是你需要根据需求,开始编写代码的地方了。

3.1.4 package.json

这个是个工程的核心配置文件,一般不需要人工改动,依赖主要包括生产和开发(devDependencies),安装或者卸载依赖时是自动维护的,这里我们关注的是scripts部分

3.1.5 运行

vite dev

什么都没干,一秒多,有点吓人

3.1.6 查看运行结果

看看,跑起来了,牛逼不😊。搓它几下,计数器变了

3.2 有ts结构

讲到这里,我又忘记ts语法了,那玩意不一直用,过不了多久就全忘记了,实在是语法过于烧脑。

3.2.1 index.html

<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>test-react-app2</title> </head> <body> <div id="root"></div> <script type="module" src="/src/main.tsx"></script> </body> </html>

注意文件后缀变成了tsx

3.2.2 main.tsx

这个文件感觉命名成index.tsx会更恰当。但是默认是这个名字就是算了

import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' import './index.css' import App from './App.tsx' /*文件后缀变成tsx*/ createRoot(document.getElementById('root')!).render( <StrictMode> <App /> </StrictMode>, )

3.2.3 App.tsx

import { useState } from 'react' import reactLogo from './assets/react.svg' import viteLogo from './assets/vite.svg' import heroImg from './assets/hero.png' import './App.css' function App() { const [count, setCount] = useState(0) return ( <> <section id="center"> <div className="hero"> <img src={heroImg} className="base" width="170" height="179" alt="" /> <img src={reactLogo} className="framework" alt="React logo" /> <img src={viteLogo} className="vite" alt="Vite logo" /> </div> <div> <h1>Get started</h1> <p> Edit <code>src/App.tsx</code> and save to test <code>HMR</code> </p> </div> <button type="button" className="counter" onClick={() => setCount((count) => count + 1)} > Count is {count} </button> </section> <div className="ticks"></div> <section id="next-steps"> <div id="docs"> <svg className="icon" role="presentation" aria-hidden="true"> <use href="/icons.svg#documentation-icon"></use> </svg> <h2>Documentation</h2> <p>Your questions, answered</p> <ul> <li> <a href="https://vite.dev/" target="_blank"> <img className="logo" src={viteLogo} alt="" /> Explore Vite </a> </li> <li> <a href="https://react.dev/" target="_blank"> <img className="button-icon" src={reactLogo} alt="" /> Learn more </a> </li> </ul> </div> <div id="social"> <svg className="icon" role="presentation" aria-hidden="true"> <use href="/icons.svg#social-icon"></use> </svg> <h2>Connect with us</h2> <p>Join the Vite community</p> <ul> <li> <a href="https://github.com/vitejs/vite" target="_blank"> <svg className="button-icon" role="presentation" aria-hidden="true" > <use href="/icons.svg#github-icon"></use> </svg> GitHub </a> </li> <li> <a href="https://chat.vite.dev/" target="_blank"> <svg className="button-icon" role="presentation" aria-hidden="true" > <use href="/icons.svg#discord-icon"></use> </svg> Discord </a> </li> <li> <a href="https://x.com/vite_js" target="_blank"> <svg className="button-icon" role="presentation" aria-hidden="true" > <use href="/icons.svg#x-icon"></use> </svg> X.com </a> </li> <li> <a href="https://bsky.app/profile/vite.dev" target="_blank"> <svg className="button-icon" role="presentation" aria-hidden="true" > <use href="/icons.svg#bluesky-icon"></use> </svg> Bluesky </a> </li> </ul> </div> </section> <div className="ticks"></div> <section id="spacer"></section> </> ) } export default App

上面这个内容有点多,不用太关注。本质和无ts是一样的

3.2.4 package.json

多了一些typescript的开发依赖

3.2.5 运行

3.2.6 查看运行结果

这个图标看起来有点酷炫

3.2.7 tsconfig.json

这是 TypeScript 项目的根配置文件,也是编译器首先寻找的文件。

  • 核心作用:它通常不直接写具体的编译选项,而是作为整个项目的“解决方案”入口。它的主要任务是通过references字段来引用其他配置文件(也就是下面的两个文件),从而将不同环境的配置分离开来。
  • 好处:这种结构让项目结构更清晰,避免了所有配置都堆在一个文件里,也方便了构建工具进行增量编译
{ "files": [], "references": [ { "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" } ] }

引用了其他两个文件

3.2.8 tsconfig.app.json

这个文件专门用于配置前端应用代码的编译选项。适用代码:你项目里所有的 React/Vue 组件、页面、工具函数等最终会在浏览器中运行的代码。

典型配置:

  • target: 设置编译后的 JavaScript 版本,例如 ESNext 或 ES2015,以兼容现代浏览器。
  • lib: 指定项目需要包含的库定义文件,如 ["DOM", "ESNext"],告诉 TypeScript 代码会运行在浏览器环境中。
  • jsx: 配置如何处理 JSX 语法,例如 react-jsx。

3.2.9 tsconfig.node.json

这个文件专门用于配置Node.js 环境下代码的编译选项。

  • 适用代码:你的项目构建脚本和配置文件,最典型的就是vite.config.ts。这些文件不是给浏览器运行的,而是给 Node.js 执行的。
  • 典型配置
    • target: 通常设置为ESNext或一个较高的 Node.js 版本,因为现代 Node.js 支持很多新特性。
    • module: 设置模块系统,如ESNextCommonJS,以适应 Node.js 的模块加载方式。
    • types: 可能会包含["node"],以引入 Node.js 的全局类型定义(如process,__dirname等)。

文件名角色定位负责范围
tsconfig.json总指挥引用其他配置,管理整个项目
tsconfig.app.json前端专员浏览器环境代码 (React/Vue 组件等)
tsconfig.node.json后端/工具专员Node.js 环境代码 (vite.config.ts 等)

3.3 .vscode目录

这个目录其实是一个重要目录,因为里面一些配置在开发中通常会用到。创建项目时并不会创建该

这个目录作用和产生机制可以参看文章

总结

加了TypeScript的之后,整个框架会复杂很多,越复杂的东西以后迁移维护成本越高。TypeScript从目前趋势来看,都是要集成的。所有弱类型变成强类型之后AI和代码提示等工具就会智能化很多,包括Python(类型提示)。动态类型、非面向对象语言严重缺点也暴露了出来。没有类型提示,光看函数签名,估计什么信息也看不出来。

现在前端框架演变的越来越复杂了,光各种插件和配置文件就够得搞半天。那些要求全栈、PC、手机、还要懂硬件的公司比周扒皮还强上十倍不止。

4 框架重构

框架布局估计会按vue的调整的目录结构重构,默认的目录结果分类不太好。

5 开发调试

开发调试和vue差不多的,请参看前面写过文章

6 格式化插件

可以参看前面写过文章。使用Prettier。最好不要配置成保存就自动格式化,使用手动选择格式化保存,不然遇到幺蛾子很麻烦。

7 路由集成

8 状态管理

react Props存在Props Drilling问题,也就是层层传递有几种非常成熟的方案可以完美避开这个Props Drilling问题:

  • Context API(官方原生方案)
    React 自带的“任意门”。你可以把数据放在顶层的Context里,深层组件直接通过useContext获取,完全不需要中间组件参与传递。非常适合传递主题、用户登录状态等全局数据。
  • 组件组合(Component Composition)
    利用children属性。有时候不需要传数据,直接把需要数据的深层组件作为children传给顶层,由顶层包一层渲染出来,也能绕过中间层级。
  • 状态管理库(如 Zustand, Redux, Jotai 等)
    当应用变得非常复杂时,可以使用专门的状态管理库。它们相当于在组件树之外建了一个“公共仓库”,任何组件都可以随时去仓库里存取数据,彻底摆脱层层传递的束缚。

9 请求组件

10 PC UI组件

11 移动端UI 组件

总结

http://www.jsqmd.com/news/825952/

相关文章:

  • fre:ac免费音频转换器:跨平台终极指南与实用教程
  • 综合能源系统多级环式一体化设计【附代码】
  • 给老人的火车票打个折,挺好,但差了点什么
  • MySQL 配置文件(my.ini/my.cnf)核心参数详解,新手必改配置
  • 令牌管理实战:从JWT原理到token-ninja库的集成与应用
  • OpenContext开源框架:模块化设计实现AI上下文管理新范式
  • 甘蓝中耕除草机器人结构与运动控制【附代码】
  • 【flutter for open harmony】第三方库Flutter 鸿蒙版 心情日记 实战指南(适配 1.0.0)✨
  • 为 OpenClaw 智能体框架配置 Taotoken 作为模型供应商的要点
  • DeepSeek在MMLU基准测试中狂揽86.7分:这3个被99%开发者忽略的推理优化技巧,立竿见影!
  • 基于Gemini CLI的深度研究工具:命令行AI助手的架构与实战
  • 【DeepSeek Chat功能测试全链路指南】:20年AI工程师亲测的7大核心场景验证法
  • 训练篇第6节:NCCL(三)——性能调优:NVLink vs. PCIe vs. InfiniBand
  • Qt 主窗口全家桶:菜单栏、工具栏、状态栏与对话框完全指南
  • GaN飞跨电容三电平逆变器调制与均压【附代码】
  • 概率计算与RRAM硬件在分子对接中的应用与优势
  • 服务器入侵应急处置:痕迹清理、漏洞封堵与事后加固全流程
  • 线程相关知识
  • 12 - AI Native“基因测序法”:你的产品是“数字生命”还是“行尸走肉”?
  • 训练篇第7节:混合并行实战——以Megatron-LM和DeepSpeed为例剖析3D并行
  • ContextGit:为代码库注入结构化上下文,提升代码可追溯性与团队协作效率
  • 绝缘子缺陷检测数据集2148张VOC+YOLO格式
  • 中小企业云上安全从零搭建:低成本防护架构落地指南
  • Arm Ethos-U85 NPU架构解析与边缘AI优化实践
  • 使用go-ios运行fastbot
  • DNS优化实战:从运营商DNS到HttpDNS的进化之路
  • MySQL 登录报错排查:1045、2003 错误,新手快速解决
  • 软件交付质量与风险管理的关键指标与实践
  • 汽车电源管理系统:同步降压转换器与LDO技术解析
  • Flutter for OpenHarmony列表刷新加载实战