Skip to content

React 基础 ​

React 概述 ​

React 是用于构建用户界面的 JavaScript 库,由 Facebook 开源。

特点 ​

  • 组件化开发 — 将 UI 拆分为独立、可复用的组件
  • 虚拟 DOM — 通过虚拟 DOM 对比,最小化真实 DOM 操作,提升性能
  • JSX 语法 — JavaScript 和 HTML 的混合语法
  • 单向数据流 — 数据从父组件流向子组件
  • 跨浏览器兼容

虚拟 DOM ​

虚拟 DOM 是一个轻量级的 JavaScript 对象,描述真实 DOM 的结构和属性。

state 变化 → 生成新虚拟 DOM → Diff 对比 → 批量更新真实 DOM
state 变化 → 生成新虚拟 DOM → Diff 对比 → 批量更新真实 DOM

Diff 算法 ​

  • 只进行同层比较,不跨层级
  • 不同类型节点直接替换
  • 同类型节点通过 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 Hookthis.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} />
  }
}