React 组件: 受控与非受控组件

283 阅读2分钟

受控与非受控

随缘更新...随缘拓展...

在 React 当中有一对相对组件概念:受控组件非受控组件。官方推荐我们使用受控组件,而不是非受控组价。

React 中什么是受控组件[1]

很多初学React不明白受控组件非受控组件[2]有什么区别。其实一句话就明白了:开发人员要组件要控制什么?

当然是 state, 也就是数据了。我们知道 React 当中 state 在数据展示和更新中扮演重要的角色。React 是通过 state 和 state 的变化 来控制视图层数据的展示和更新任务。所以控制其实是通过 state 来控制 React 程序。从源码的层面,组件数据更新都是通过调用 Component.prototype.update/forceUpdate[3] 来更新 state,从而控制程序的。

受控组件实例

一个简单的受控组件的例子。

我们所写的 React 组件一般都是都是受控组件(就好比"道"长存于心,但不知"道"), 以下 state.a定义更新的过程就是在 React 的控制范围内,因此 Article 组件即受控组件

import React, { Component } from 'react'
class Article extends Component {
    state = {
        a: 1
    }
    
    handleChange() {
        this.state += 1
    }
    
    render() {
        let { a } = this.state
        return (
            <>
                <div>{a}</div>
                <button onClick={this.handleChange.bind(this)}>点我state + 1</button>
            </>
        )
    }
}

非受控组件实例

React 实际使用了虚拟 DOM 来节省了 DOM 的消耗,但是真的我们就不在需要直接操作DOM了吗?

答案是否定的。

因为我们在 Raect 当中难免会引入第三方库(DOM库),难免有触发动画等等需要操作DOM。也就是说声明式的操作 DOM 是避免不了的。React ref[2:1] 就提供了触碰 DOM 的能力,在构建非受控组件起到很大的作用, 下面是官方的对比的例子:

class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
    // 创建一个 ref 来存储 textInput 的 DOM 元素
    this.textInput = React.createRef();
    this.focusTextInput = this.focusTextInput.bind(this);
  }

  focusTextInput() {
    // 直接使用原生 API 使 text 输入框获得焦点
    // 注意:我们通过 "current" 来访问 DOM 节点
    this.textInput.current.focus();
  }

  render() {
    // 告诉 React 我们想把 <input> ref 关联到
    // 构造器里创建的 `textInput` 上
    return (
      <div>
        <input
          type="text"
          ref={this.textInput} />

        <input
          type="button"
          value="Focus the text input"
          onClick={this.focusTextInput}
        />
      </div>
    );
  }
}

何时使用受控组件

  1. React 当中推荐使用受控组件, React hooks 出来之后,更加推荐使用 hooks 的函数式受控组件。

何时使用非受控组件

  1. 需要处理与 DOM 相关的操作时,一般配合 Ref 来获取 DOM。

参考


  1. react.docschina.org/docs/forms.… ↩︎

  2. react.docschina.org/docs/uncont… ↩︎ ↩︎

  3. github.com/facebook/re… ↩︎