青戈AI小栈
会员限时8折
React 零基础入门

创建 React 项目与第一个商品页面

9,197 字约 23 分钟读完38 次阅读更新于 2026/10/22

登录后收藏

阅读设置

字号
行距
代码

本课程从一个商品页面开始,逐步学习组件、数据展示、事件、状态和表单,再通过接口请求数据,完成商品与分类管理。本节结束时,可以创建并启动 React 项目,在浏览器中显示第一张商品卡片,并通过修改代码更新页面内容。

开始前需要会什么

本课程面向第一次学习 React 的开发者,不要求学过 Vue 或其他前端框架。“零基础”指 React 开发零基础,开始前需要了解:

  • HTML 的标题、段落、链接等基本标签。
  • CSS 的选择器、颜色、字号和内外边距。
  • JavaScript 的变量、对象、数组、函数和返回值。

如果只学过 Python,建议先补充 HTML、CSS 和 JavaScript 的基本用法。课程中首次用到解构、数组方法和异步请求时,会结合具体功能解释。

React、Vite 和 Node.js 各自负责什么

React是用于构建用户界面的 JavaScript 库。页面可以拆成多个组件,例如商品卡片、搜索框和新增商品表单。组件将相关的显示内容和交互逻辑组织在一起。

本节先编写一个名为 App 的组件,让它显示商品信息。后续再根据数据和用户操作改变页面。

Vite 提供开发服务器和构建工具。开发时,它将项目中的代码处理后交给浏览器;保存代码后,浏览器可以更新对应内容。课程使用 Vite 创建 React 项目。

Node.js让 JavaScript 可以在浏览器之外运行,本节用它运行 Vite 等开发工具。安装 Node.js 时会同时安装npm,用来下载项目依赖和执行项目命令。

安装开发工具

以下步骤以 Windows 10/11、VS Code 和 PowerShell 为例。

安装 Node.js

打开 Node.js 官方下载页,选择 Node.js 24 LTS 系列的 Windows 安装程序。普通 Intel/AMD 的 64 位电脑选择 x64;ARM 电脑选择 ARM64。下载 .msi 安装程序,按安装向导完成安装,保留 npm 和添加到 PATH 的选项。

PATH 是系统查找命令时使用的目录列表。将 Node.js 加入 PATH 后,才能直接在终端输入 node 和 npm。

本节示例在 Node.js 24.16.0、npm 11.13.0 下验证。Vite 要求 Node.js 20.19 以上,或 22.12 以上,详见 Vite 官方中文文档,Node.js 24 LTS 满足要求。已经安装 Node.js 的读者,先完成下一小节的版本检查,版本不满足要求时再重新安装。

安装 VS Code 并打开终端

从 VS Code 官方下载页(英文) 下载 Windows 安装程序并完成安装。React 项目需要编辑 .jsx、.js 和 .css 文件,VS Code 已提供这些文件的基本支持。

安装 Node.js 后,重新打开 VS Code,让新进程读取更新后的 PATH。

按 Ctrl+Shift+P 打开命令面板,输入 Terminal: Select Default Profile,选择 PowerShell。再通过菜单 Terminal > New Terminal(终端 > 新建终端)打开终端。

在终端逐条执行:

powershell
node --version
npm --version

本节验证环境中的输出分别为:

输出
v24.16.0
11.13.0

小版本不同可能显示其他数字,关键是两条命令都能正常输出版本。

如果提示无法识别 node 或 npm,先关闭并重新打开 VS Code;仍然失败时,重新运行 Node.js 安装程序,确认安装了 npm 并添加到 PATH。

创建 React 项目

准备项目所在文件夹

在资源管理器中新建一个存放课程工程的文件夹,例如 D:\Course。如果电脑没有 D 盘,也可以在其他磁盘创建 Course 文件夹。后续路径以实际选择的位置为准。

在 VS Code 中选择 File > Open Folder(文件 > 打开文件夹),打开这个文件夹。

通过 Terminal > New Terminal 新建终端,确认提示符中的当前目录为 D:\Course。如果使用了其他位置,以实际打开的文件夹为准。

这里先打开的是项目的上一级目录,下一条命令会在其中新建 react-demo。

生成项目文件

在终端执行:

powershell
npx create-vite@9.2.1 react-demo --template react --no-interactive

第一次使用时,npx 可能询问是否安装 create-vite@9.2.1,输入 y 并回车。命令会联网下载项目创建工具。

按顺序理解命令中的内容:

  • npx create-vite@9.2.1:运行指定版本的 create-vite 项目创建工具。
  • react-demo:新建项目的文件夹名称。
  • --template react:选择 React 的 JavaScript 模板。
  • --no-interactive:使用命令中指定的选项创建项目,不进入模板选择问答。

这里的 9.2.1 是项目创建工具的版本,和 React、Vite 本身的版本不同。

本节没有使用 npm create vite@9.2.1 react-demo -- --template react --no-interactive 这种常见写法。在 PowerShell 7.6.0 中实测,这条命令后半部分的选项没有传给创建工具,终端仍然进入“Select a framework”问答。如果执行后出现这个选择界面,按 Ctrl+C 退出,再执行上面的 npx 命令。

创建完成后,左侧会出现 react-demo 文件夹,终端会提示进入项目、安装依赖和启动服务。接下来按下面的步骤打开项目,再执行安装与启动命令。

如果当前目录已经有同名的 react-demo,先确认它是否就是此前创建的课程项目。已有项目可直接打开继续,不要在包含自己文件的目录中反复创建或选择清空目录。

打开项目并安装依赖

在 VS Code 中再次选择 File > Open Folder,打开刚生成的 D:\Course\react-demo。左侧资源管理器的顶层文件夹应变成 react-demo。

新建终端,确认当前目录为 react-demo,并能在左侧看到 package.json。后续命令都在这个项目根目录执行。

执行:

powershell
npm install

依赖是项目需要使用的第三方代码,例如 React 和 Vite。package.json 记录这个项目需要哪些依赖,npm install 根据它下载依赖。

安装完成后会生成 node_modules 目录和 package-lock.json 文件。前者保存下载后的依赖,后者记录实际安装的完整版本,应与项目代码一起保留。node_modules 中的文件由 npm 管理,不需要手动修改。

本节验证时使用 React 19.3.1、Vite 8.3.4。模板中的版本范围可能允许安装后续兼容版本,以项目生成的 package-lock.json 为准。

安装时保持网络连接,等待命令执行完成、终端重新出现可输入命令的提示符,再继续下一步。

启动并打开页面

在 react-demo 项目根目录执行:

powershell
npm run dev

package.json 的 scripts 区域为常用命令起名字,npm run dev 就是执行其中名为 dev 的命令。当前模板中,dev 对应 vite,作用是启动开发服务器。

默认使用 5173 端口,启动成功后,终端的 Local 一行通常显示:

输出
http://localhost:5173/

打开 Chrome 或 Edge,在地址栏输入终端显示的 Local 地址。当前模板会显示带有 Vite、React 标识和计数按钮的初始页面,说明开发服务器已启动,浏览器已经加载 React 应用。

Vite 初始页面中的 React、Vite 标识和 Count is 0 计数按钮

localhost 表示当前电脑,端口号用于区分本机正在运行的不同服务。默认端口被占用时,Vite 会尝试其他端口,以终端实际显示的地址为准。不要双击 index.html,应通过开发服务器地址访问项目。

服务运行期间,这个终端会一直显示运行信息,不会回到普通命令提示符,这是正常现象。暂时保留它,接下来可以直接编辑文件。

后面排查问题会用到浏览器的开发者工具:在页面上按 F12,切换到 Console(控制台)标签,代码运行出错时,详细信息会显示在这里。

修改第一个组件

先在左侧资源管理器展开 src 文件夹。本节会修改其中的 App.jsx、index.css 和 App.css:

文件 用途
src/App.jsx 编写要显示的商品界面
src/index.css 设置整个页面的通用样式
src/App.css 设置商品页面和卡片的样式

这些文件已经由模板生成,直接打开修改即可。正文中的 src/App.jsx 表示“项目根目录下 src 文件夹中的 App.jsx”,文件名和大小写需要保持一致。

先让页面显示一句话

在左侧资源管理器打开 src/App.jsx,将文件全部内容替换为:

jsx
export default function App() {
  return <h1>商品管理</h1>
}

按 Ctrl+S 保存,再回到浏览器。页面会变成“商品管理”,原来的标识和计数按钮消失。此时仍可能沿用模板的背景和居中样式,后面会统一调整。

App 是一个 JavaScript 函数,返回要显示的内容。React 将这样的函数作为组件使用:

  • function App():声明名为 App 的函数,React 组件名称以大写字母开头。
  • return:返回当前组件的界面内容。
  • <h1>商品管理</h1>:返回一级标题。
  • export default:将 App 作为当前文件的默认导出,供其他文件导入。

写在 JavaScript 中、形似 HTML 标签的语法叫 JSX。Vite 会处理它,让浏览器能够执行。.jsx 后缀帮助开发工具识别包含 JSX 的 JavaScript 文件。

后续再展开 JSX 的具体规则。本节先使用正确闭合的标签,通过 return 返回组件要显示的内容。可以结合 React 官方中文快速入门 查阅组件和 JSX 的基本写法。

代码中的两个空格表示缩进,用于看清哪些内容属于函数内部。后面出现嵌套标签时,也会用缩进表示层次。

用 main 包住页面主体

接下来要在标题下面加入商品卡片,先为这些内容准备一个共同的外层容器。

main 是 HTML 标签,表示页面的主要内容区域。商品管理标题和商品卡片都属于本页主体,所以放在 <main>...</main> 中。以后页面加入导航栏或页脚时,这些公共区域通常放在 main 外面。一个页面通常只保留一个可见的 main,便于屏幕阅读器定位主体内容。

React 没有要求最外层必须使用 main,通用容器 div 也能包住这些内容。选择 main 是为了说明“这是页面主体”。这种用标签表达内容用途的写法,称为 HTML 语义化。

将 src/App.jsx 的全部内容替换为:

jsx
export default function App() {
  return (
    <main className="page">
      <h1>商品管理</h1>
    </main>
  )
}

return 后面的括号将多行 JSX 组织在一起,左括号与 return 写在同一行。最外层的 main 包住页面内容,后面新增的商品卡片也放在它里面。

className 为标签指定 CSS 类名,作用对应 HTML 中的 class。这里的 page 是自行起的类名,稍后通过 .page 选择器设置样式。main 和类名本身不会自动生成背景或居中效果。

保存后,页面仍然只显示“商品管理”。这一步增加的是页面结构,还没有增加新的可见文字。

显示第一张商品卡片

在 h1 后面加入一张商品卡片。卡片使用 article 标签,表示一块可以独立理解的内容;这里的名称、价格、库存和上架状态构成完整的商品信息。

卡片中的 h2 是二级标题,用作商品名称;p 是段落,用来显示每一项商品资料。页面的 h1 表示“商品管理”,卡片中的 h2 表示其中的一件商品,两者通过标题级别表达层次。

下面是修改后的完整 src/App.jsx,将文件全部内容替换为它:

jsx
import './App.css'

export default function App() {
  return (
    <main className="page">
      <h1>商品管理</h1>
      <article className="product-card">
        <h2>矿泉水</h2>
        <p>价格:¥3.50</p>
        <p>库存:100 件</p>
        <p>上架状态:已上架</p>
      </article>
    </main>
  )
}

import './App.css' 加载当前目录中的样式文件。路径中的 ./ 表示当前文件所在目录,这里对应 src/App.css。

product-card 也是自行起的类名,用来单独设置卡片样式。查看 JSX 的缩进可以看出:标题和卡片都在 main 里面,商品名称和三个段落又在 article 里面。

保存后先核对新增的文字是否出现。此时仍在使用模板的样式,背景、文字颜色和间距会在下一步统一调整。

现在的商品名称、价格和库存都是固定文字。修改源文件并保存才会改变它们;通过输入框或按钮更新商品,留到后续讲到事件与状态时再介绍。

替换模板样式

打开 src/index.css,将全部内容替换为:

css
* {
  box-sizing: border-box;
}

body {
  margin: 0;
  min-width: 320px;
  background: #f5f7fa;
  color: #1f2937;
  font-family: Arial, "Microsoft YaHei", sans-serif;
  line-height: 1.6;
}

index.css 提供页面通用样式。* 选择所有元素,box-sizing: border-box 让元素设置的宽度包含内边距与边框。body 是 HTML 中承载页面内容的元素,这里为它去掉默认外边距,并设置背景、文字颜色和字体。

min-width: 320px 作为本例页面的最小宽度,line-height: 1.6 将行高设为字号的 1.6 倍,让文字之间留出空间。

再打开 src/App.css,将全部内容替换为:

css
.page {
  max-width: 800px;
  margin: 0 auto;
  padding: 32px 16px;
}

.page h1 {
  margin: 0 0 24px;
  font-size: 28px;
}

.product-card {
  padding: 24px;
  border: 1px solid #e5e7eb;
  border-radius: 12px;
  background: #ffffff;
}

.product-card h2 {
  margin: 0 0 16px;
  font-size: 22px;
}

.product-card p {
  margin: 8px 0;
}

.page 对应 className="page",限制内容区域宽度,并通过 margin: 0 auto 居中。.product-card 对应商品卡片,设置内边距、边框和白色背景。

.product-card h2 选择卡片内部的二级标题,.product-card p 选择卡片内部的段落。padding 设置内容与边框之间的距离,margin 调整元素外部的间距。

保存后,页面应显示浅灰背景、一个“商品管理”标题和一张白色商品卡片。卡片内容为:

输出
矿泉水
价格:¥3.50
库存:100 件
上架状态:已上架

替换模板样式后,浅灰背景上的矿泉水商品卡片

只删除 App.jsx 中的模板内容不会去掉 index.css 的全局样式,因此两个 CSS 文件都需要按本节替换。

App 怎样显示到浏览器中

完成第一个页面后,再看项目入口。当前需要认识的文件如下,其他生成文件可以先保留:

输出
react-demo/
├── index.html
├── package.json
├── package-lock.json
├── vite.config.js
├── node_modules/
├── public/
└── src/
    ├── assets/
    ├── main.jsx
    ├── App.jsx
    ├── index.css
    └── App.css

模板还带有 public 与 src/assets,存放模板自带的图标等文件,本节先保留原样。

vite.config.js 是 Vite 的配置文件,模板已经配置了 React 插件,本节保留原样。main.jsx 和 index.html 决定应用从哪里加载,下面查看它们怎样使用刚才编写的 App。

项目根目录的 index.html 是浏览器加载的 HTML 入口。其中包含一个容器和一个模块脚本:

html
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>

这里摘出了已有文件中的两行用于观察,不需要将整个 index.html 替换为这两行。id="root" 标记 React 要使用的容器,script 加载 src/main.jsx;type="module" 表示以 JavaScript 模块方式加载,允许代码通过 import 引入其他模块。

打开 src/main.jsx,模板中已经有以下完整代码,本节保留原样:

jsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <App />
  </StrictMode>,
)

渲染就是让 React 根据组件描述的内容生成或更新页面。这段入口代码只需要认识三处:

  • import './index.css' 加载全局样式,import App from './App.jsx' 导入刚才编写的组件。
  • createRoot(document.getElementById('root')).render(...) 找到 index.html 中 ID 为 root 的容器,把 <App /> 显示在里面。<App /> 表示使用 App 组件,/> 是没有子内容时的自闭合写法。
  • StrictMode 在开发时启用额外检查,不会生成可见标签。本节保留模板写法,不需要修改。

{ createRoot } 的大括号表示按名称导入,import App 没有大括号,对应 App.jsx 中的默认导出。createRoot 和 StrictMode 的更多细节暂不展开,用到时再讲。

flowchart TD
    HTML["index.html:提供 root 容器"] --> ENTRY["main.jsx:找到容器,渲染 App"]
    ENTRY -->|导入组件| APP["App.jsx:定义商品界面"]
    ENTRY -->|加载全局样式| GLOBAL["index.css:全局样式"]
    APP -->|加载页面样式| CARD["App.css:商品页面样式"]
    ENTRY -->|将 App 渲染到 root| VIEW["浏览器:显示商品卡片"]

    classDef entry fill:#dbeafe,stroke:#2563eb,color:#1e3a8a;
    classDef component fill:#ede9fe,stroke:#7c3aed,color:#4c1d95;
    classDef stylesheet fill:#fef3c7,stroke:#d97706,color:#78350f;
    classDef view fill:#dcfce7,stroke:#16a34a,color:#14532d;
    class HTML,ENTRY entry;
    class APP component;
    class GLOBAL,CARD stylesheet;
    class VIEW view;

从 index.html 找到 main.jsx,再沿箭头查看它导入的组件和样式。main.jsx 最后调用渲染方法,将 App 的界面显示在 root 容器中。编辑商品内容时主要修改 App.jsx,不需要每次改动入口文件。

连续核对页面更新

保持开发服务运行,在 src/App.jsx 中将“矿泉水”改成“可乐”,将 ¥3.50 改成 ¥5.00,按 Ctrl+S 保存。

回到浏览器,不手动刷新,确认商品名和价格已更新。Vite 监听到文件变化后,会将更新交给浏览器,这称为热更新。

核对完成后,将名称和价格恢复为“矿泉水”和 ¥3.50,保存,保留课程统一的初始商品。

然后回到运行服务的终端,按 Ctrl+C 停止服务;如果终端询问是否终止批处理,输入 Y 并回车。停止后刷新浏览器,页面将无法重新连接开发服务器。

仍在项目根目录重新执行:

powershell
npm run dev

看到 Local 地址后重新加载页面,商品卡片再次显示。源文件保存在磁盘上,不会因停止开发服务而丢失。

常见问题

提示找不到 package.json 或 dev 脚本

执行 npm run dev 出现下面两种提示时,先看终端中的当前目录。常见原因是仍处于 D:\Course,而项目实际位于它下面的 react-demo。npm 会从当前目录开始,向上级目录查找 package.json,所以提示的内容取决于上级目录里有没有这个文件:

  • 当前目录和所有上级目录都没有 package.json:提示中有 Could not read package.json,错误码是 ENOENT,意思是找不到 package.json。
  • 上级目录里恰好有一个 package.json,但其中没有 dev 脚本:提示 Missing script: "dev"。

这两种提示都说明当前目录不是项目根目录。

通过 VS Code 打开 react-demo 文件夹,再新建终端,确认当前目录的 package.json 中有 "dev": "vite" 后重试。安装依赖前同样需要确认当前目录:在没有项目的目录中执行 npm install,可能同样提示 Could not read package.json;如果上级目录恰好有 package.json,npm 会把它当作当前项目,命令不报错,但依赖装进了那个上级项目,课程项目的依赖并没有安装。

启动后地址不是 5173 端口

默认端口被占用时,Vite 会自动尝试其他端口,例如 5174。直接打开本次启动后终端显示的 Local 地址即可。

若此前已在另一个终端启动同一项目,可以继续使用那个服务,或回到对应终端按 Ctrl+C 停止,避免重复启动。

修改后仍显示原来的页面

先确认 App.jsx 已保存,VS Code 标签上没有表示未保存的小圆点。再核对浏览器地址与当前终端的 Local 地址一致,避免打开另一个项目的服务。

如果旧内容已经消失,只是背景或布局仍像模板,检查 index.css 和 App.css 是否都已完整替换,以及 App.jsx 顶部是否保留 import './App.css'。

页面显示 JSX 错误

如果编辑时漏写结束标签,或误用中文引号,Vite 会在浏览器页面上盖一层错误提示,终端里也会输出同样的信息。先看提示中的文件路径与行号,再对照本节完整代码修正对应位置,保存后页面通常会自动恢复,没有恢复时按 F5 刷新。

例如 <h1>商品管理</h1> 的开始与结束标签需要配对;className="page" 中使用英文引号。出错后不要先重建项目,先修复提示定位到的源文件。

安装依赖时出现网络错误

如果安装命令因网络超时或连接失败而退出,先确认电脑可以访问网络,再在同一个 react-demo 根目录重新执行失败的安装命令。安装尚未成功时,直接启动可能提示找不到 Vite;先完成依赖安装再启动。

完成本节后,项目应能启动、显示矿泉水商品卡片,并在保存修改后更新内容。后面继续在这个项目中使用 JSX,将固定文字改为从 JavaScript 数据中读取。

有帮助
登录后提问 / 纠错

提问与反馈

仅你和管理员可见。我的反馈

设置你的昵称

在英雄榜和讨论中,使用你自己的名字。

2–12 个字符0 / 12