前言
参考资料:本文根据MDN官方文档进行讲解。
-
使用前提:React 使用称为 JSX(JavaScript 和 XML)的 HTML-in-JavaScript 语法。熟悉 HTML 和 JavaScript 可以帮助你学习 JSX,并更好地确定应用程序中的错误是与 JavaScript 还是与 React 的更特定领域相关。
-
学习目标:学习如何设置本地 React 开发环境,创建一个启动应用程序,并了解其工作原理。
创建一个React项目
掌握 React 项目的创建是开启开发之旅的第一步。
- 初始化项目:打开终端,使用
npm init vite命令,该命令会按照 Vite 提供的模版初始化项目。执行命令后,系统会提示你填写项目名称并选择项目类型和使用的语言,此时选择react作为项目类型,JavaScript作为开发语言 ,即可得到一个基于 Vite 和 React 的项目模版,后续开发将基于此展开。
- 进入项目目录:项目初始化完成后,在终端输入
cd 项目名(将 “项目名” 替换为实际创建的项目名称),进入到项目目录中。
- 安装依赖:在项目目录下,执行
npm i(这是npm install的缩写)命令,npm 会自动读取项目中的配置文件,将项目运行所需要的各种依赖包下载并安装到node_modules目录中,该目录专门用于存放项目依赖。
- 启动项目:依赖安装完成后,输入
npm run dev命令,会给你一个地址。此时,在浏览器中输入这个地址,就能看到初始的 React 项目页面。
完整过程如下:
至此,一个可进行开发的 React 项目就创建完成了。
React 项目的目录结构
通过以上步骤,在我们的指定文件下就会生成一个React项目。
一个典型的 React 项目目录结构如下:
在这个结构中:
-
node_modules:存放项目依赖的第三方包(如 React 等),由npm i命令自动安装,无需手动修改,会根据package.json中依赖配置管理包内容。 -
index.html:项目的入口 HTML 文件。 -
src:目录是开发的核心目录,所有的源代码都存放在这里。 -
components:建议存放 React 组件文件(如 TodoList 组件、TodoItem 组件等 ),用于组件化开发,将页面拆分为独立可复用的功能单元,方便维护和管理。
-
App.css:App.jsx根组件的样式文件,可编写该组件及相关子组件的 CSS 样式,实现组件样式隔离。 -
App.jsx:React 应用的根组件,是页面组件树的顶层,用于组织、渲染其他子组件,编写应用的整体布局和业务逻辑。
初识React
1. 定义:React 是一个用于构建用户界面的库。
2. 目标:最大程度地减少开发人员构建 UI 时发生的错误。
3. 实现:它通过使用组件(描述部分用户界面的、自包含的逻辑代码段)来实现此目的。这些组件可以组合在一起以创建完整的 UI,React 将许多渲染工作进行抽象化,使你可以专注于界面设计。
一、开发工具:npm 与 Vite
1.1 npm:包管理利器
npm(Node Package Manager) 是 JavaScript 生态重要的 包管理工具。在 React 开发中,它能轻松安装、更新 Redux、React Router 等第三方依赖包,自动处理依赖关系,保障项目稳定运行,同时也是创建 React 项目的必备工具。
1.2 Vite:高效工程化套件
Vite 是 React 项目开发的得力助手,类似 “塔吊” 和 “搅拌机”,能快速搭建项目框架,处理代码转换、打包等复杂工作,提供简洁模版代码,让开发者快速启动项目,专注业务逻辑实现。
二、深入理解 React 组件
2.1 什么是组件
在 React 中,组件是将 HTML、JavaScript 和 CSS 组合在一起的开发单元。它就像是构成页面的一个个 “积木块”,每个组件都有自己独立的功能和逻辑。
例如,在一个待办事项应用中,App.jsx 通常是根组件,它就像整个应用的 “总指挥”,负责协调和管理其他组件。
但如果我们将所有的代码都写在根组件中,会导致代码过于庞大和复杂。这时,就需要将功能进行拆分,以TodoList组件为例,它将待办事项相关的功能封装在一起,成为一个独立的工作和功能单位。
2.2 从 DOM 树编程到组件树编程
在传统的前端开发中,我们常常直接操作 DOM 树来更新页面内容,这种方式不仅繁琐,而且容易出错。
而 React 采用了组件化思想,将页面抽象为组件树,通过组件的状态和属性变化来自动更新 DOM。这种方式使得开发者可以更专注于业务逻辑的实现,而不需要花费大量精力去操作 DOM API。
2.3 函数式组件:简洁高效的开发方式
函数式组件是 React 中最常用的组件形式之一。一个函数式组件本质上就是一个 JavaScript 函数,它接收一些数据(props)作为输入,然后返回一段 JSX 代码(类似 HTML 的语法)。
在函数中,我们可以在return之前声明数据和处理业务逻辑,return时将数据绑定到 JSX 模版中。例如:
function Todos(props){
// 如何拿到父组件传过来的数据状态呢? - 传参
const todos = props.todos
return(
<ul>
{
todos.map(todo=>(
<li key={todo.id}>{todo.text}</li>
))
}
</ul>
)
}
export default Todos;
代码解析
效果图:
这段代码实现了一个基础的待办事项列表应用,由三个核心组件构成:App、TodoList 和 TodoForm,我们来看看它们是如何联系起来的:
组件关系概览
-
App组件(根组件)- 作为整个应用的入口,渲染
TodoList组件。 - 无状态,仅负责组件组合。
- 作为整个应用的入口,渲染
-
TodoList组件(状态管理核心)- 管理待办事项的状态(
todos)和标题(title)。 - 提供添加待办的方法(
handleAdd)。 - 渲染
TodoForm(表单输入)和Todos(列表展示)。
- 管理待办事项的状态(
-
TodoForm组件(表单输入)- 负责处理用户输入和表单提交。
- 通过回调函数(
onAdd)将输入数据传递给父组件(TodoList)。
-
Todos组件(列表展示)- 接收父组件传递的
todos数据并渲染列表。
- 接收父组件传递的
完整代码注解
// App.jsx - 应用根组件
import { useState } from 'react'
import './App.css'
import TodoList from './components/TodoList'
function App() {
// 作为应用的根组件,负责组合其他核心组件
// 本应用中只渲染TodoList组件,实际项目可能包含更多组件
return (
<>
{/* 渲染TodoList组件,该组件管理待办事项的核心逻辑 */}
<TodoList />
</>
)
}
export default App
// TodoList.jsx - 待办事项列表的核心管理组件
import { useState } from 'react'
import '../Todo.css'
import TodoForm from './TodoForm' // 导入表单组件
import Todos from './Todos' // 导入列表展示组件
function TodoList() {
// 状态管理:使用useState钩子创建和管理组件状态
const [title, setTitle] = useState('Todo List') // 页面标题状态
const [todos, setTodos] = useState([ // 待办事项列表状态,初始有一个示例项
{
id: 1,
text: '吃饭',
completed: false
},
])
// 添加新待办事项的处理函数
const handleAdd = text => {
// 使用展开运算符保留原有数据,并添加新的待办事项
// 自动生成id,使用当前数组长度+1
setTodos([
...todos,
{
id: todos.length + 1,
text, // ES6简写,等同于text: text
completed: false
}
])
}
return (
<div className="container">
<h1 className="title">{title}</h1>
{/*
渲染表单组件,并通过props传递handleAdd函数
子组件(TodoForm)可以通过onAdd属性调用此函数
*/}
<TodoForm onAdd={handleAdd} />
{/*
渲染列表展示组件,通过props传递todos数据
Todos组件将根据这些数据渲染待办事项列表
*/}
<Todos todos={todos} />
</div>
);
}
export default TodoList;
// TodoForm.jsx - 负责处理用户输入的表单组件
import { useState } from "react";
function TodoForm(props) {
// 从父组件接收onAdd函数,用于提交新待办事项
const onAdd = props.onAdd;
// 管理输入框的本地状态,初始值为"打豆豆"
const [text, setText] = useState('打豆豆');
// 表单提交处理函数
const handleSubmit = e => {
// 阻止表单默认提交行为,避免页面刷新
e.preventDefault();
// 调用父组件传递的回调函数,将当前输入的文本传递给父组件
onAdd(text);
// 提交后清空输入框
setText('');
}
// 输入框内容变化处理函数
const handleChange = e => {
// 获取输入框的当前值,并更新本地状态
setText(e.target.value);
}
return (
<form action="#" onSubmit={handleSubmit}>
<input
type="text"
placeholder="请输入待办事项"
value={text} // 将输入框的值与状态绑定
onChange={handleChange} // 绑定变化处理函数
/>
<button type="submit">添加</button>
</form>
)
}
export default TodoForm;
// Todos.jsx - 负责渲染待办事项列表的纯展示组件
function Todos(props) {
// 从父组件接收todos数据
const todos = props.todos
return (
<ul>
{/* 使用map方法遍历todos数组,为每个待办事项创建一个列表项 */}
todos.map(todo => (
// 每个列表项必须有唯一的key属性,优化React渲染性能
<li key={todo.id}>{todo.text}</li>
))
</ul>
)
}
export default Todos;
结尾
要成为一名合格的前端开发者,掌握组件化开发和响应式数据状态管理是关键。通过不断学习和实践,熟练运用 React 的各种特性和工具,就能开发出功能丰富、性能良好的前端应用。
通过以上内容,相信你对 React 已经有了一个初步的了解。接下来,不妨亲自尝试创建一个简单的 React 项目,在实践中加深对这些概念的理解和掌握。随着学习的深入,你会发现 React 的更多强大功能和应用场景,开启精彩的前端开发之旅。