React 基础
React 概述
React 是用于构建用户界面的 JavaScript 库,由 Facebook 开源。
特点
- 组件化开发 — 将 UI 拆分为独立、可复用的组件
- 虚拟 DOM — 通过虚拟 DOM 对比,最小化真实 DOM 操作,提升性能
- JSX 语法 — JavaScript 和 HTML 的混合语法
- 单向数据流 — 数据从父组件流向子组件
- 跨浏览器兼容
虚拟 DOM
虚拟 DOM 是一个轻量级的 JavaScript 对象,描述真实 DOM 的结构和属性。
state 变化 → 生成新虚拟 DOM → Diff 对比 → 批量更新真实 DOMstate 变化 → 生成新虚拟 DOM → Diff 对比 → 批量更新真实 DOMDiff 算法
- 只进行同层比较,不跨层级
- 不同类型节点直接替换
- 同类型节点通过 key 优化比较
JSX 语法
JSX 是 JavaScript 的语法扩展,遇 <> 解析为 HTML,遇 {} 解析为 JavaScript。
基本规则
jsx
// 必须有且仅有一个根元素(可用 Fragment:<></>)
// 单标签必须自闭合
// class 用 className,for 用 htmlFor
// 使用 map 循环渲染,必须加 key
const element = <h1>Hello, {name}!</h1>
const list = (
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
)// 必须有且仅有一个根元素(可用 Fragment:<></>)
// 单标签必须自闭合
// class 用 className,for 用 htmlFor
// 使用 map 循环渲染,必须加 key
const element = <h1>Hello, {name}!</h1>
const list = (
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
)createElement
jsx
React.createElement('button', { className: 'btn' }, '点击')
// 等价于 JSX:
<button className="btn">点击</button>React.createElement('button', { className: 'btn' }, '点击')
// 等价于 JSX:
<button className="btn">点击</button>条件渲染
jsx
{condition && <Component />}
{condition ? <A /> : <B />}{condition && <Component />}
{condition ? <A /> : <B />}样式方案
jsx
// 内联样式(驼峰命名,px 可直接写数字)
<div style={{ color: 'red', fontSize: 16 }} />
// CSS 模块化
import styles from './style.module.css'
<div className={styles.wrapper} />
// 动态 class
<div className={`icon ${active ? 'active' : ''}`} />
<div className={active ? styles.active : ''} />
// dangerouslySetInnerHTML(渲染 HTML 内容)
<div dangerouslySetInnerHTML={{ __html: htmlContent }} />// 内联样式(驼峰命名,px 可直接写数字)
<div style={{ color: 'red', fontSize: 16 }} />
// CSS 模块化
import styles from './style.module.css'
<div className={styles.wrapper} />
// 动态 class
<div className={`icon ${active ? 'active' : ''}`} />
<div className={active ? styles.active : ''} />
// dangerouslySetInnerHTML(渲染 HTML 内容)
<div dangerouslySetInnerHTML={{ __html: htmlContent }} />key 值
- 使用唯一标识(如 id),避免使用索引
- 禁止使用
Math.random()作为 key
组件创建方式
函数组件
jsx
function Welcome(props) {
return <h1>Hello, {props.name}</h1>
}
// 箭头函数
const Welcome = (props) => <h1>Hello, {props.name}</h1>function Welcome(props) {
return <h1>Hello, {props.name}</h1>
}
// 箭头函数
const Welcome = (props) => <h1>Hello, {props.name}</h1>类组件
jsx
import React, { Component } from 'react'
class Welcome extends Component {
state = { count: 0 }
render() {
return <h1>Count: {this.state.count}</h1>
}
}import React, { Component } from 'react'
class Welcome extends Component {
state = { count: 0 }
render() {
return <h1>Count: {this.state.count}</h1>
}
}区别:
| 特性 | 函数组件 | 类组件 |
|---|---|---|
| state | 使用 useState Hook | this.state |
| 生命周期 | 使用 useEffect Hook | 生命周期方法 |
| 性能 | 更轻量 | 略重 |
| 推荐度 | 推荐 | 历史遗留 |
State 与 setState
定义 state
jsx
// 声明式
class App extends Component {
state = { count: 0, name: 'React' }
}
// 构造函数
class App extends Component {
constructor(props) {
super(props)
this.state = { count: 0 }
}
}// 声明式
class App extends Component {
state = { count: 0, name: 'React' }
}
// 构造函数
class App extends Component {
constructor(props) {
super(props)
this.state = { count: 0 }
}
}setState 使用
jsx
// 对象形式
this.setState({ count: 10 }, () => {
console.log('更新完成')
})
// 函数形式(保证 state 和 props 最新)
this.setState((prevState, props) => ({
count: prevState.count + 1
}))// 对象形式
this.setState({ count: 10 }, () => {
console.log('更新完成')
})
// 函数形式(保证 state 和 props 最新)
this.setState((prevState, props) => ({
count: prevState.count + 1
}))setState 特性
- 合成事件中是异步的(React 批处理机制)
- 生命周期中是异步的
- 定时器中是同步的
- 原生事件中是同步的
jsx
// 多次 setState 合并
this.setState({ count: this.state.count + 1 })
this.setState({ count: this.state.count + 1 })
// 结果:只加 1(合并为一次)
// 函数形式避免合并
this.setState((prev) => ({ count: prev.count + 1 }))
this.setState((prev) => ({ count: prev.count + 1 }))
// 结果:加 2// 多次 setState 合并
this.setState({ count: this.state.count + 1 })
this.setState({ count: this.state.count + 1 })
// 结果:只加 1(合并为一次)
// 函数形式避免合并
this.setState((prev) => ({ count: prev.count + 1 }))
this.setState((prev) => ({ count: prev.count + 1 }))
// 结果:加 2事件处理
事件绑定
jsx
// 推荐:箭头函数
class App extends Component {
handleClick = () => {
console.log('点击')
}
render() {
return <button onClick={this.handleClick}>点击</button>
}
}// 推荐:箭头函数
class App extends Component {
handleClick = () => {
console.log('点击')
}
render() {
return <button onClick={this.handleClick}>点击</button>
}
}事件传参
jsx
// 箭头函数传参
<button onClick={() => this.handleClick('参数')}>点击</button>
// bind 传参
<button onClick={this.handleClick.bind(this, '参数')}>点击</button>// 箭头函数传参
<button onClick={() => this.handleClick('参数')}>点击</button>
// bind 传参
<button onClick={this.handleClick.bind(this, '参数')}>点击</button>受控组件 vs 非受控组件
受控组件
由 State 控制 value 的表单元素:
jsx
class App extends Component {
state = { value: '' }
handleChange = (e) => {
this.setState({ value: e.target.value })
}
render() {
return <input value={this.state.value} onChange={this.handleChange} />
}
}class App extends Component {
state = { value: '' }
handleChange = (e) => {
this.setState({ value: e.target.value })
}
render() {
return <input value={this.state.value} onChange={this.handleChange} />
}
}非受控组件
通过 ref 操作 DOM:
jsx
class App extends Component {
inputRef = React.createRef()
handleSubmit = () => {
console.log(this.inputRef.current.value)
}
render() {
return <input ref={this.inputRef} />
}
}class App extends Component {
inputRef = React.createRef()
handleSubmit = () => {
console.log(this.inputRef.current.value)
}
render() {
return <input ref={this.inputRef} />
}
}
Cao Note