(三)React技术核心思想——组件化编程
一、从生活案例理解:什么是组件?
想象你要组装一台电脑:主机箱里有主板、CPU、显卡,显示器有屏幕、支架,这些"独立的、有特定功能的零件"就是组件。最后把这些零件拼在一起,就成了能正常工作的电脑。
React中的"组件"和这个逻辑完全一样:
组件是"具有独立功能的、可复用的代码块",是构成页面的最小功能单元。一个完整的页面,就是由多个组件像搭积木一样组合而成的。
举个网页的例子:
一个电商详情页可以拆成这些组件:
- 导航栏组件(包含logo、搜索框、购物车按钮)
- 商品图片组件(展示商品大图)
- 商品信息组件(包含标题、价格、库存)
- 加入购物车组件(按钮和数量选择器)
- 评价列表组件(展示用户评论)
- 页脚组件(包含联系方式、版权信息)
每个组件只负责自己的功能(比如"加入购物车组件"只处理点击加入和数量修改),最后组合起来就是完整的页面。
二、为什么React要强调组件化?—— 解决开发痛点
假设不用组件化开发一个电商网站,你可能会写出这样的代码:
一个HTML文件里堆了几千行代码,所有功能(导航、商品、评论)的HTML、CSS、JS混在一起。
- 想改一下按钮样式?要在几千行代码里找对应的CSS;
- 另一个页面也需要同样的导航栏?复制粘贴一大段代码,改一处地方要改所有复制的版本;
- 新人接手项目?看代码看到头大,根本不知道哪部分对应哪部分功能。
而组件化能完美解决这些问题,核心优势有3点:
1. 复用性:写一次,到处能用
比如你写了一个"蓝色按钮"组件,只要在需要的地方"调用"它就行,不用重复写HTML和样式。
哪怕要改样式,只需要改这一个组件文件,所有用到它的地方都会自动更新。
2. 可维护性:责任清晰,改起来放心
每个组件只负责自己的功能,代码量少且独立。比如"评价列表组件"出了问题,只需要检查这个组件的代码,不用担心影响导航栏或购物车功能。
3. 协作高效:多人分工,互不干扰
大型项目中,多个开发者可以同时开发不同的组件(比如A开发导航栏,B开发商品信息),最后拼在一起就行,不会因为改了同一文件而冲突。
三、React组件的两种基本形式:函数组件 vs 类组件
React中有两种定义组件的方式,初学者首先要掌握函数组件(现在React官方更推荐),类组件作为了解即可。
1. 函数组件(重点!)
本质:一个返回React元素(JSX)的JavaScript函数。
最简单的函数组件长这样:
// 定义一个函数组件(函数名首字母必须大写!)
function Welcome() {// 返回要显示的内容(JSX语法,后面详细讲)return <h1>欢迎学习React组件化!</h1>;
}
函数组件的核心规则:
- 函数名必须首字母大写(React通过这个区分组件和普通HTML标签,比如
<Welcome>
是组件,<div>
是普通标签); - 函数必须返回一个React元素(通常是JSX,也可以是null);
- 函数内部可以包含逻辑(比如计算、条件判断),但最终要返回用于展示的内容。
2. 类组件(了解即可)
基于ES6的class语法定义的组件,需要继承React.Component
,并实现render()
方法返回内容。
基本形式:
// 导入React(旧版本必须,新版本可省略)
import React from 'react';// 定义类组件(类名首字母大写)
class Welcome extends React.Component {// 必须有render()方法,返回要显示的内容render() {return <h1>欢迎学习React组件化!</h1>;}
}
类组件和函数组件的简单对比:
特点 | 函数组件 | 类组件 |
---|---|---|
语法 | 像普通函数,简洁 | 基于class,代码量稍多 |
状态管理 | 用React Hooks(后续课程讲) | 用this.state和this.setState |
适用场景 | 大部分场景(推荐优先使用) | 复杂场景(逐步被函数组件替代) |
初学者建议:先专注学函数组件,90%的基础场景用函数组件就能搞定。
四、JSX:组件的"模板语言"(必须掌握!)
上面的组件例子中,返回的<h1>欢迎学习React组件化!</h1>
不是普通HTML,而是JSX(JavaScript XML的缩写)。
它是React提供的一种语法糖,允许你在JavaScript中直接写类似HTML的代码,最终会被编译成浏览器能理解的普通JavaScript。
为什么需要JSX?
如果不用JSX,想创建一个包含标题的React元素,需要写这样的代码:
// 不用JSX的写法(繁琐)
return React.createElement('h1', null, '欢迎学习React组件化!');
而用JSX,写法和HTML几乎一样,大大简化了代码。
JSX和HTML的异同(重点!)
相同点:
- 基本标签写法一致(比如
<div>
、<p>
、<h1>
); - 标签嵌套规则一致(必须有闭合,比如
<img />
、<input />
)。
不同点(容易踩坑!):
-
class属性要写成className
因为class
是JavaScript的关键字(用于定义类),所以JSX中用className
代替:// 错误写法(会报错) <div class="box">内容</div>// 正确写法 <div className="box">内容</div>
-
事件名要驼峰式命名
比如HTML中的onclick
,在JSX中要写成onClick
;onchange
写成onChange
:// 错误写法 <button onclick="handleClick()">点击</button>// 正确写法 <button onClick={handleClick}>点击</button>
-
样式要用对象形式
内联样式不能直接写字符串,要写成JavaScript对象(属性名驼峰式):// 错误写法 <div style="color: red; font-size: 16px;">内容</div>// 正确写法 <div style={{ color: 'red', fontSize: '16px' }}>内容</div> // 外层{}表示"这里是JavaScript",内层{}是样式对象
-
必须有一个根节点
JSX返回的内容必须被一个根节点包裹(如果不想多一个div,可以用<>
和</>
空标签,称为Fragment):// 错误写法(多个根节点) return (<h1>标题</h1><p>段落</p> );// 正确写法(用div包裹) return (<div><h1>标题</h1><p>段落</p></div> );// 更简洁的写法(用空标签Fragment) return (<><h1>标题</h1><p>段落</p></> );
-
可以直接嵌入JavaScript变量
用{}
包裹变量或表达式,就能在JSX中显示动态内容:function Welcome() {const name = "张三"; // 定义变量return (<h1>欢迎{name}学习React!</h1> // 用{}嵌入变量); } // 页面会显示:欢迎张三学习React!
五、组件的使用:导入、导出与组合
定义好的组件,需要"导出"才能被其他组件使用,使用时需要"导入",最后像HTML标签一样写在JSX中。
步骤1:创建并导出组件
通常一个组件放在一个单独的文件中(方便管理),文件名和组件名保持一致(首字母大写)。
比如创建一个Header.js
文件(放在src
目录下):
// src/Header.js
// 定义Header组件
function Header() {return (<header className="header"><h1>我的React博客</h1><nav><a href="/">首页</a><a href="/about">关于</a></nav></header>);
}// 导出组件(默认导出)
export default Header;
导出方式说明:
export default 组件名
:默认导出,一个文件只能有一个默认导出;- 导入时可以自定义名称(但通常和组件名一致)。
步骤2:导入并使用组件
在需要使用组件的文件中(比如App.js
),先导入组件,再像用HTML标签一样使用(注意首字母大写)。
修改src/App.js
:
// src/App.js
// 导入Header组件(从Header.js文件)
import Header from './Header';// 定义App组件(根组件)
function App() {return (<div>{/* 使用Header组件,就像用HTML标签一样 */}<Header />{/* 其他内容 */}<main><p>这是博客的正文内容</p></main></div>);
}export default App;
步骤3:运行效果
启动项目(npm start
),浏览器会显示:
- 顶部的Header组件内容("我的React博客"标题和导航链接);
- 下面的正文内容。
这就是组件的组合:App组件包含了Header组件,形成了完整的页面结构。
再试一个:创建多个组件并组合
再创建一个Footer.js
组件:
// src/Footer.js
function Footer() {return (<footer><p>© 2024 我的React博客 版权所有</p></footer>);
}export default Footer;
在App.js
中导入并使用:
// src/App.js
import Header from './Header';
import Footer from './Footer'; // 导入Footer组件function App() {return (<><Header /><main><p>这是博客的正文内容</p></main><Footer /> {/* 使用Footer组件 */}</>);
}export default App;
现在页面结构更完整了:Header(头部)→ main(正文)→ Footer(底部),完全由组件组合而成。
六、动手实践:写一个"用户卡片"组件
让我们综合练习一下,创建一个UserCard.js
组件,展示用户信息(头像、姓名、简介),然后在App中使用。
步骤1:创建UserCard.js
// src/UserCard.js
function UserCard() {// 组件内部可以定义数据const user = {name: "李四",avatar: "https://picsum.photos/200", // 随机头像图片bio: "前端学习者,正在学习React组件化"};return (<div className="user-card" style={{ border: '1px solid #ddd', padding: '20px', borderRadius: '8px', maxWidth: '300px' }}>{/* 头像 */}<img src={user.avatar} alt={user.name} style={{ width: '100px', borderRadius: '50%' }}/>{/* 姓名 */}<h3 style={{ color: '#333' }}>{user.name}</h3>{/* 简介 */}<p style={{ color: '#666' }}>{user.bio}</p></div>);
}export default UserCard;
步骤2:在App.js
中使用
// src/App.js
import Header from './Header';
import Footer from './Footer';
import UserCard from './UserCard'; // 导入UserCard组件function App() {return (<><Header /><main style={{ padding: '20px' }}><h2>用户列表</h2>{/* 多次使用UserCard组件,体现复用性 */}<UserCard /><UserCard /> {/* 同一个组件可以用多次 */}</main><Footer /></>);
}export default App;
运行效果:
页面会显示两个相同的用户卡片(因为组件复用了),每个卡片有头像、姓名和简介,被边框包裹,样式统一。
这就是组件复用的好处:如果想修改卡片样式,只需要改UserCard.js
一个文件,所有卡片都会更新。
七、常见错误与解决办法
-
组件名小写导致报错
错误写法:function userCard() { ... }
,使用时<userCard />
原因:React会把小写标签当作普通HTML标签(比如<div>
),而HTML中没有userCard
标签,所以报错。
解决:组件名首字母必须大写,function UserCard() { ... }
,使用时<UserCard />
。 -
JSX返回多个根节点
错误写法:function App() {return (<Header /><Footer />); }
解决:用
<>
和</>
包裹:function App() {return (<><Header /><Footer /></>); }
-
忘记导出/导入组件
错误:在UserCard.js
中没写export default UserCard
,或在App.js
中没写import UserCard from './UserCard'
报错:'UserCard' is not defined
解决:检查导出和导入语句是否正确,文件名和路径是否匹配(./
表示当前目录)。
八、本节课总结
重点回顾:
- 组件是"具有独立功能的可复用代码块",页面由组件组合而成,像搭积木;
- 函数组件是返回JSX的函数,首字母必须大写,是React推荐的写法;
- JSX是React的模板语法,类似HTML但有区别(className、驼峰事件名、样式对象等);
- 组件通过
export default
导出,通过import
导入,使用时像HTML标签一样写在JSX中; - 组件的核心优势是复用性、可维护性和协作效率。