🐾
组件受控与非受控

什么是受控组件与非受控组件?

在了解这两个概念之前,你需要知道 JSX 是什么。

JSX

JSXJavaScript 的语法扩展,它可以让我们在 JS 中编写类似 HTML 的代码。

看起来像这样:

const element = <div>hello, world</div>

我们可以给 element 赋一个 div,看起来很奇怪,但这就是 JSX 语法。可以将 JSHTML 写在一起。

不过,需要注意的是这里的 div 并不是原生 DOM

写在 HTML 文档中的 HTML 标签是原生 DOM,而写在 JSX 中的 HTML 标签是 JSX 元素。

JSX 元素在项目构建的时候会被 babel 转换。

上面定义的 element 在转换之前是这样的:

<div>hello, world</div>

经过 babel 转换后是这样的:

import { jsx as _jsx } from 'react/jsx-runtime'
/*#__PURE__*/ _jsx('div', {
  children: 'hello, world'
})

babelJSX 元素转换成了一个 React 元素的创建操作,函数 _jsx 创建了一个与真实 DOM 结构对应的 React 元素, 这个根据真实 DOM 结构抽象出来的对象,即我们常说的虚拟 DOM。结构是这样的:

{
  $$typeof: Symbol(react.element),
  key: null,
  props: {
    children: 'hello, world'
  },
  ref: null,
  type: 'div'
}

element 虚拟 DOM 的标签类型是 div,子元素是文本元素 'hello, world',其描述了真实 DOM 的结构。

虚拟 DOM 转为真实 DOM 是通过 react-dom 库实现的。

受控与非受控

React 中,组件的状态可分为:受控和非受控。

受控和非受控的区别在于组件的状态是由谁来控制的。

简单来说:

组件状态由外部控制的就是受控组件,由内部控制的就是非受控组件。

React 里,如果一个组件的状态是由 props 控制的,那么这个组件就是受控组件。 如果这个组件的状态是由内部 state 控制的,那么这个组件就是非受控组件。

React 中,组件分为:

  • 内置浏览器组件:比如 divinputform 等。
  • 自定义组件:开发者自己实现的函数组件或类组件。

注意 React 的内置浏览器组件并不是原生 DOM,它们实际上是 React 元素。在 JSX 部分我们已经讲过了。

下面我们看一个受控浏览器组件的例子:

组件 <input> 的状态 value 完全由 onChange 事件控制。

function ControlledInput() {
  const [inputValue, setInputValue] = useState('')
 
  const handleInputChange = event => {
    setInputValue(event.target.value)
  }
 
  return <input type="text" value={inputValue} onChange={handleInputChange} />
}

再来看一个非受控浏览器组件的例子:

组件 <input> 的状态由组件自身管理,组件的数据更新不需要外部控制,我们通过 ref 获取它的值。

function UncontrolledInput() {
  const inputRef = useRef(null)
 
  const handleButtonClick = () => {
    console.log(inputRef.current.value)
  }
 
  return (
    <div>
      <input type="text" ref={inputRef} />
      <button onClick={handleButtonClick}>打印 input 值</button>
    </div>
  )
}

MIT 2024 © Binghuis