第一次接触 React 时,可能会被 JSX 函数组件 状态管理这些概念绕晕。其实,只要抓住一个简单的例子,把里面的细节拆开来看,你会发现这些概念非常自然。
下面就通过一个小小的根组件示例,来系统梳理:
- 函数组件是什么、为什么适合做组件
- JSX 的本质是什么
useState如何管理组件状态- 列表渲染、条件渲染怎么写
- 事件处理和交互逻辑如何组织
前言
JSX 是 JavaScript XML 的缩写,是 React 引入的语法扩展(并非新语言),允许你在 JavaScript 代码中直接书写类似 HTML 的标记语法,用于描述 React 组件的 UI 结构。
简单来说:JSX = JavaScript + HTML 语法糖,它不是直接运行在浏览器中的,会被 Babel 等工具编译为标准的 JavaScript 代码(React.createElement 调用),最终生成 React 能识别的虚拟 DOM。
一、组件:用函数组合 JS / HTML / CSS
// useState -> React 的核心 Hook,相当于 vue 中的ref
// createElement -> 创建虚拟 DOM 的函数,JSX 最终会被编译为 createElement 调用
import { useState , createElement} from 'react';
// 导入组件的样式文件,实现样式隔离。
import './App.css';
在这个示例里,根组件本质上就是一个普通的 JavaScript 函数:
function RootComponent() {
// 一些状态和逻辑
return (
<>
{/* 一些 JSX UI */}
</>
);
}
几个关键点:
-
组件是函数
输入是 props 和内部状态,输出是 UI 描述(JSX)。
函数天然适合做组件:1、 有清晰输入输出
2、 容易复用
3、 易于拆分和组合成组件树
-
组件是 JS / HTML / CSS 的组合
1、 JS:状态、计算逻辑、事件处理
2、 HTML:通过 JSX 写结构
3、 CSS:通过类名和样式文件控制样式
这个示例组件就把“问候语”“待办清单”“登录状态”等 UI 和业务逻辑,都放在一个函数体里组织,非常直观。
二、JSX:语法糖背后还是 createElement
const element = <h2>故事的小黄花,从出生那年就飘着</h2>;
const element2 = createElement('h2', null, '故事的小黄花,从出生那年就飘着');
这两行是等价的,说明了几点:
-
JSX 是语法糖
<h2>...</h2>会在编译阶段被转换成createElement('h2', ...)- JSX 只是让我们写 UI 更接近 HTML,提升可读性和开发效率
-
“XML in JS”
本质是在 JS 里写一种“类似 XML 的结构描述”,最终都是 JS 对象。 -
类名用
className
在 JSX 中不能写class="title",因为class是 JS 关键字,要写成className="title":<span className="title">{name}</span>
三、useState:React 版 “ref”
组件中用了三个状态:
const [name, setName] = useState('杰伦');
const [todos, setTodos] = useState([
{ id: 1, title: '晴天', done: false },
{ id: 2, title: '稻香', done: false },
]);
const [isLoggedIn, setIsLoggedIn] = useState(false);
理解这段解构代码,只需要记住一句话:
useState返回一个数组:
第一个是当前状态值,第二个是更新状态的函数。
这和 Vue 里的 ref 很像:都用来维护某个“响应式值”。
1. 状态驱动 UI
在代码中:
name控制问候语中的歌手名字todos控制待办列表的渲染isLoggedIn控制“已登录 / 未登录”提示和按钮文案
每次调用对应的 setXxx,React 会触发一次重新渲染,UI 自动更新。
2. 状态的异步更新例子
组件里有这样一段逻辑:
setTimeout(() => {
setName('Jay Chou');
}, 3000);
含义是:组件渲染后 3 秒,把 name 从“杰伦”改成 “Jay Chou”,UI 随之更新。
真实项目中,更推荐把这种副作用放进 useEffect,但作为演示:
它很直观地展示了“修改状态 → 触发重渲染 → UI 自动变化”的流程。
四、列表渲染:用 map 生成节点
代码中的待办列表通过 map 来渲染:
todos.length > 0 ? (
<ul>
{todos.map(todo => (
<li key={todo.id}>
{todo.title}
</li>
))}
</ul>
) : (
<div>暂无待办事项</div>
)
可以总结几个实战要点:
- 用
map生成列表
数组里的每一项,映射成一个 JSX 节点,非常自然。 key必须写
key={todo.id}帮助 React 高效地识别每个列表项,避免不必要的 DOM 操作。- 和条件渲染结合
todos.length > 0 ? ... : ...
有内容就显示列表,没有内容就显示“暂无待办事项”。
五、条件渲染:三元表达式写 UI 分支
除了列表,组件还通过条件渲染来展示登录状态:
{isLoggedIn ? <div>已登录</div> : <div>未登录</div>}
搭配按钮文本:
<button onClick={toggleLogin}>
{isLoggedIn ? '退出登录' : '登录'}
</button>
onClick={toggleLogin} 是 React 的事件绑定方式,和原生 JavaScript、Vue 的事件绑定在语法形式、底层实现、事件机制上都有明显区别。
在 React 的JSX 中绑定事件时,必须使用驼峰命名(比如
onClick、onChange、onMouseEnter)
六、事件处理:把交互逻辑写成函数
登录状态的切换逻辑被抽成了一个函数:
const toggleLogin = () => {
setIsLoggedIn(!isLoggedIn);
};
然后绑定到按钮的 onClick 上:
<button onClick={toggleLogin}>
{isLoggedIn ? '退出登录' : '登录'}
</button>