Skip to content

第三章 静态组件与动态组件

内容前瞻

本章将深入探讨 静态组件动态组件 的区别与实现方式,涵盖组件的封装、状态管理、生命周期、更新机制以及高阶组件(HOC)等内容。重点包括:

  • 静态组件:函数组件的特点与应用场景。
  • 动态组件:类组件与 Hooks 组件的生命周期与状态管理。
  • 组件更新机制setState 的异步批处理与渲染优化。
  • 高阶组件:HOC 的应用场景与实现方式。

静态组件与动态组件

1. 静态组件(函数组件)

  • 特点
    • 基于函数实现,无法基于内部状态实现视图更新。
    • 适用于不需要动态更新、只需渲染一次的场景。
  • 渲染过程
    • 初次渲染:从函数作用域中解析 props(冻结),生成虚拟 DOM(VDOM)并渲染。
    • 后续操作:只更新作用域中的数据,不会触发组件内容的重新渲染。
  • 动态化
    • 通过 Hooks(如 useStateuseEffect)实现状态管理与视图更新。
    • 父组件传递不同的 props,子组件会相应更新。

示例

jsx
function StaticComponent(props) {
  return <div>{props.message}</div>;
}

function ParentComponent() {
  const [message, setMessage] = React.useState('Hello');
  return (
    <div>
      <StaticComponent message={message} />
      <button onClick={() => setMessage('Updated')}>Update</button>
    </div>
  );
}

2. 动态组件

  • 类组件
    • 生命周期
      • 初次渲染getDefaultProps -> getInitialState -> componentWillMount -> render -> componentDidMount
      • 后续更新shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate
    • 状态初始化
      • state 自动挂载到实例上,默认为 null
      • 通过 setState 更新状态并触发视图更新。
    • 强制更新forceUpdate 跳过 shouldComponentUpdate,直接触发重新渲染。

示例

jsx
class DynamicComponent extends React.Component {
  state = { count: 0 };

  handleClick = () => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.handleClick}>Increment</button>
      </div>
    );
  }
}
  • Hooks 组件
    • 通过 useStateuseEffect 等 Hooks 实现状态管理与生命周期。

组件更新机制

1. setState 的异步批处理

  • React 18:所有 setState 均为异步操作。
  • React 16:合成事件与 Hooks 中为异步,setTimeout、DOM 事件等为同步。
  • 更新逻辑
    • shouldComponentUpdate -> componentWillUpdate -> 更新数据 -> render -> componentDidUpdate
  • 回调机制
    • this.setState(partialState, callback)callback 在状态更新后触发,类似于 Vue 的 $nextTick

示例

jsx
this.setState({ count: 1 }, () => {
  console.log('State updated');
});

2. flushSync

  • 作用:立即处理状态更新队列。
  • 使用场景:需要同步更新状态的场景。

示例

jsx
import { flushSync } from 'react-dom';

flushSync(() => {
  this.setState({ count: 1 });
});

受控组件与非受控组件

1. 受控组件

  • 特点:通过修改数据驱动视图更新。
  • 示例:表单输入框的值由 state 控制。

示例

jsx
function ControlledComponent() {
  const [value, setValue] = React.useState('');
  return <input value={value} onChange={(e) => setValue(e.target.value)} />;
}

2. 非受控组件

  • 特点:通过 ref 获取 DOM 元素,直接操作 DOM。
  • 实现方式
    • this.refs.xxx:通过字符串 ref 获取 DOM。
    • ref={(dom) => { this.xxx = dom }}:通过回调函数获取 DOM。
    • React.createRef():创建 ref 对象,ref.current 获取 DOM。

示例

jsx
function UncontrolledComponent() {
  const inputRef = React.useRef(null);
  return <input ref={inputRef} />;
}

高阶组件(HOC)

1. HOC 的应用场景

  • 类组件中使用 JSS:通过 HOC 代理样式处理。
  • 通用逻辑复用:如权限校验、日志记录等。

2. HOC 的实现

  • 高阶函数:内部返回函数的函数,通过闭包实现函数代理。
  • 示例
    jsx
    function withLogger(WrappedComponent) {
      return function (props) {
        console.log('Rendered:', WrappedComponent.name);
        return <WrappedComponent {...props} />;
      };
    }
    
    const EnhancedComponent = withLogger(MyComponent);

重难点 & 容易忽视的点

1. PureComponent

  • 特点:继承 PureComponent 后,自动实现 shouldComponentUpdate 的浅对比。
  • 注意:显式使用 shouldComponentUpdate 会导致警告。

2. 事件委托机制

  • React 16:事件委托给 document
  • React 17+:事件委托给 #root
  • 优势:减少事件绑定数量,提升性能。

3. 合成事件

  • 特点onXxx 事件通过 React 封装,支持事件委托。
  • 传参:事件对象为最后一个参数。

总结

  • 静态组件:适用于无需动态更新的场景,通过 Hooks 实现动态化。
  • 动态组件:类组件与 Hooks 组件支持状态管理与生命周期。
  • 更新机制setState 的异步批处理与 flushSync 的同步更新。
  • HOC:通过高阶函数实现逻辑复用与组件增强。