什么是 React?
React 是由 Facebook(现在的 Meta)开发的一个用于构建用户界面的 JavaScript 库。它的核心思想是组件化开发,让我们可以像搭积木一样组合组件来构建网页。
React 的特点
- 组件化:将页面拆分成独立的、可复用的组件
- 声明式:只需要描述 UI 应该是什么样子,React 会自动更新
- 高效:使用虚拟 DOM 技术,只更新变化的部分
1. React 项目结构
入口文件:main.jsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
// 挂载根组件
// react 一开始就是组件思想,非常的纯粹
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>,
)
解释:
main.jsx是应用的入口文件createRoot创建一个 React 根节点render方法将组件渲染到页面上<App />是我们的根组件,所有其他组件都是它的子组件StrictMode是 React 的严格模式,帮助我们发现潜在问题
2. 什么是 JSX?
JSX 是 JavaScript XML 的缩写,它是 React 中用于描述用户界面的语法扩展。
JSX 文件后缀
在 React 中,我们使用 .jsx 作为文件后缀(也可以使用 .js,但 .jsx 更明确表示这是 React 组件)。
JSX 的本质
JSX 主要是为了简化模板开发,提升代码的可读性。它看起来像 HTML,但实际上是 JavaScript。
// JSX 写法(推荐)
const element = <h2>JSX 是React 中用于描述用户界面的语法扩展</h2>
// 等价于原生 JavaScript(不推荐)
const element2 = createElement('h2', null, 'JSX 是React 中用于描述用户界面的语法扩展')
JSX 的优势:
- 更直观,像写 HTML 一样
- 更容易理解和维护
- 编译时会自动转换成 JavaScript
JSX 的规则
-
最外层只能有一个元素
// 正确:用一个 div 包裹 return ( <div> <h1>标题</h1> <p>内容</p> </div> ) // 错误:两个并列的元素 return ( <h1>标题</h1> <p>内容</p> ) -
使用 Fragment(文档碎片)包裹多个元素
// 使用 <> </> 包裹(推荐) return ( <> <h1>标题</h1> <p>内容</p> </> ) -
使用 className 而不是 class
// 正确 <div className="title">Hello</div> // 错误(class 是 JavaScript 关键字) <div class="title">Hello</div> -
使用大括号 {} 嵌入 JavaScript 表达式
const name = "React" return <h1>Hello {name}</h1> // 输出:Hello React
3. 组件(Component)
什么是组件?
组件是由 js/css/html 组合起来,完成一个相对独立的功能。
组件是 React 开发的基本单位。函数将 JSX + 逻辑封装成一个组件,JSX 负责 UI(用户界面)。
组件的定义方式
方式一:函数声明(推荐)
function App() {
return <h1>Hello React</h1>
}
方式二:箭头函数
const App = () => {
return <h1>Hello React</h1>
}
注意: 在 React 中,函数就是组件。JavaScript 没有 class(虽然 ES6 有,但 React 推荐使用函数组件)。
组件的特点
- 返回 JSX 的函数就是 组件
- 组件可以像 HTML 标签一样使用
- 组件可以组合:大组件由小组件组成,形成组件树
4. 组件化开发 - 像搭积木一样
传统前端开发 vs React 开发
传统前端:
- HTML 标签、CSS 规则是开发的基本单位
- 就像建筑里的砖头和沙子
React 开发:
- 组件是开发的基本单位
- 就像包工头,先分工(组件化),然后组件组合起来组成网页
- 组件化让我们像搭积木一样组合成页面
实际例子:组件组合
// 头部组件
function JuejinHeader() {
return (
<div>
<header>
<h1>JueJin首页</h1>
</header>
</div>
)
}
// 文章列表组件
const Articles = () => {
return (
<div>
Articles
</div>
)
}
// 签到组件
const Checkin = () => {
return (
<div>
Check in
</div>
)
}
// 热门文章组件
const TopArticles = () => {
return (
<div>
TopArticles
</div>
)
}
// 根组件:组合所有子组件
function App2() {
return (
<div>
{/* 头部组件 */}
<JuejinHeader />
<main>
{/* 组件也和html一样声明,自定义组件 */}
{/* 组件化让我们像搭积木一样组合成页面 */}
<Articles />
<aside>
<Checkin />
<TopArticles />
</aside>
</main>
</div>
)
}
说明:
- 每个组件负责一个独立的功能
- 在根组件中,我们可以像使用 HTML 标签一样使用自定义组件
<JuejinHeader />就是使用我们定义的组件
5. 状态管理 - useState
什么是状态(State)?
State(状态) 是组件的数据。当状态改变时,React 会自动更新页面。
useState Hook
useState 是 React 提供的一个 Hook(钩子函数),用于在函数组件中添加状态。
import { useState } from 'react'
function App() {
// useState 返回一个数组:[状态值, 更新状态的函数]
const [name, setName] = useState("vue")
return <h1>Hello {name}</h1>
}
解释:
useState("vue")创建一个初始值为 "vue" 的状态name是当前状态的值setName是更新状态的函数- 当调用
setName("react")时,name会变成 "react",页面会自动更新
多个状态
一个组件可以有多个状态:
function App() {
const [name, setName] = useState("vue")
const [isLoggedIn, setIsLoggedIn] = useState(false)
const [todos, setTodos] = useState([
{
id: 1,
title: "学习react",
done: false,
},
{
id: 2,
title: "学习node",
done: false,
}
])
// ...
}
状态更新示例
// 3秒后自动更新状态
setTimeout(() => {
setName("react")
}, 3000)
当 3 秒后执行 setName("react") 时,页面上的 {name} 会自动从 "vue" 变成 "react"。
6. 事件处理
事件处理函数
在 React 中,事件处理使用 onClick、onChange 等属性(注意是驼峰命名)。
function App() {
const [isLoggedIn, setIsLoggedIn] = useState(false)
// 定义事件处理函数
const toggleLogin = () => {
setIsLoggedIn(!isLoggedIn) // 切换登录状态
}
return (
<button onClick={toggleLogin}>
{isLoggedIn ? "退出登录" : "登录"}
</button>
)
}
重要提示:
- 使用
onClick而不是onclick(React 使用驼峰命名) - 事件处理函数用大括号包裹:
onClick={toggleLogin} - 不要加括号:
onClick={toggleLogin}而不是onClick={toggleLogin()}
7. 条件渲染
条件渲染就是根据条件决定显示什么内容。
三元运算符
{isLoggedIn ? <div>已登录</div> : <div>未登录</div>}
解释:
- 如果
isLoggedIn为true,显示 "已登录" - 如果
isLoggedIn为false,显示 "未登录"
逻辑与运算符
{todos.length > 0 ? (
<ul>
{/* 列表内容 */}
</ul>
) : (
<div>暂无待办事项</div>
)}
解释:
- 如果
todos.length > 0(有待办事项),显示列表 - 否则显示 "暂无待办事项"
8. 列表渲染
使用 map 方法渲染列表。
const [todos, setTodos] = useState([
{
id: 1,
title: "学习react",
done: false,
},
{
id: 2,
title: "学习node",
done: false,
}
])
return (
<ul>
{todos.map((todo) => (
<li key={todo.id}>
{todo.title}
</li>
))}
</ul>
)
重要提示:
- 使用
map方法遍历数组 - 必须给每个列表项添加
key属性,且key应该是唯一的(通常使用id) key帮助 React 识别哪些项改变了,提高渲染效率
9. 完整示例
让我们看一个完整的组件示例:
import { useState, createElement } from 'react'
import './App.css'
function App() {
// 状态定义
const [name, setName] = useState("vue")
const [isLoggedIn, setIsLoggedIn] = useState(false)
const [todos, setTodos] = useState([
{
id: 1,
title: "学习react",
done: false,
},
{
id: 2,
title: "学习node",
done: false,
}
])
// 3秒后更新 name
setTimeout(() => {
setName("react")
}, 3000)
// 事件处理函数
const toggleLogin = () => {
setIsLoggedIn(!isLoggedIn)
}
// JSX 元素
const element = <h2>JSX 是React 中用于描述用户界面的语法扩展</h2>
return (
// 使用 Fragment 包裹多个元素
<>
{element}
<h1>Hello <span className="title">{name}</span></h1>
{/* 条件渲染:列表 */}
{todos.length > 0 ? (
<ul>
{todos.map((todo) => (
<li key={todo.id}>
{todo.title}
</li>
))}
</ul>
) : (
<div>暂无待办事项</div>
)}
{/* 条件渲染:登录状态 */}
{isLoggedIn ? <div>已登录</div> : <div>未登录</div>}
{/* 事件处理 */}
<button onClick={toggleLogin}>
{isLoggedIn ? "退出登录" : "登录"}
</button>
</>
)
}
export default App
10. 总结
React 的核心概念
- 组件化:将页面拆分成独立的组件
- JSX:用类似 HTML 的语法写 JavaScript
- 状态管理:使用
useState管理组件数据 - 事件处理:使用
onClick等属性处理用户交互 - 条件渲染:根据条件显示不同内容
- 列表渲染:使用
map渲染数组数据
React 开发流程
- 设计组件结构:将页面拆分成组件
- 定义组件:用函数定义每个组件
- 添加状态:使用
useState管理数据 - 处理交互:添加事件处理函数
- 组合组件:在根组件中组合所有子组件
常见问题
为什么 React 使用 JSX?
A: JSX 让代码更直观,像写 HTML 一样,提升代码可读性。它会被编译成 JavaScript。
组件必须返回 JSX 吗?
A: 是的,组件必须返回 JSX(或 null)。返回 JSX 的函数就是组件。
什么时候使用 useState?
A: 当你需要存储会变化的数据,并且希望数据变化时页面自动更新,就使用 useState。
key 属性为什么重要?
A: key 帮助 React 识别列表中的每个元素,当列表变化时,React 可以高效地更新 DOM。