React 受控组件与非受控组件
#
受控组件 非受控组件- 受控组件:指
DOM
元素的值受react
的状态控制 - 非受控组件:指
DOM
元素的值不受react
的状态控制
#
受控组件改变受控组件input
的值 有两种方式,
- 使用
defaultValue
<input defaultValue={this.state.text} />
- 使用
onChange
事件
<input value={this.state.text} onChange={this.handler} />
而解决报错有以下三种方式:
- 使用
defaultValue
<input defaultValue={this.state.text} />
- 使用
readOnly
只读 (只解决报错,不实现功能)
<input value={this.state.text} readOnly />
- 使用
onChange
事件
<input value={this.state.text} onChange={this.handler} />
import React from 'react';import { render } from 'react-dom';/* Failed prop type: You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`. */class TextInput extends React.Component { constructor(prpos) { super(prpos); this.state = { text: "1" } } handler = (event) => { this.setState({ text: event.target.value }) } render() { return <> <input value={this.state.text} onChange={this.handler} /> </> }}render(<TextInput></TextInput>, window.root);
#
非受控组件ref老版方式
ref
老版方式一:
// refs已弃用import React from 'react';import { render } from 'react-dom';//非受控组件 ref 老版方式一:class Sum extends React.Component { constructor(prpos) { super(prpos); this.state = { text: "1" } } add = () => { let a = this.refs.a.value let b = this.refs.b.value let sum = parseFloat(a) + parseFloat(b) this.refs.c.value = sum console.log(this.refs.a); } render() { return <> <input ref="a" />+ <input ref="b" /> <button onClick={this.add}>等于</button> <input ref="c" /> </> }}
render(<Sum></Sum>, window.root);
ref
老版方式二:
import React from 'react';import { render } from 'react-dom';//非受控组件 ref 老版方式二class Sum extends React.Component { constructor(prpos) { super(prpos); this.state = { text: "1" } } add = () => { let a = this.a.value let b = this.b.value let sum = parseFloat(a) + parseFloat(b) this.c.value = sum } render() { return <> <input ref={a => this.a = a} /><input ref={b => this.b = b} /> <button onClick={this.add}>等于</button> <input ref={c => this.c = c} /> </> }}
render(<Sum></Sum>, window.root);
- 非受控组件
createRef
(新版方式)
ref
可以是DOM
元素的引用也可以是组件的引用.
- 引入
import React, { createRef } from 'react'
- 初始化
constructor() { super() //初始化 ref createRef() this.refA = createRef() // 组件里面使用 refA '定义的ref'}
- 使用
reactDOM
元素中写: ref={this.refA}
<input ref={this.refA} />+<input ref={this.refB} />
取值和赋值 属性会放在current
上面
- 案例
import React, { createRef } from 'react';import { render } from 'react-dom';//非受控组件 createRefclass Sum extends React.Component { constructor() { super() //初始化ref createRef this.refA = createRef() this.refB = createRef() this.refC = createRef() } add = () => { console.log(this.refA); let A = this.refA.current.value let B = this.refB.current.value this.refC.current.value = parseFloat(A) + parseFloat(B) } render() { return <> <input ref={this.refA} />+<input ref={this.refB} /> <button onClick={this.add}>=</button> <input ref={this.refC} /> </> }}render(<Sum a="4"></Sum>, window.root);
- 类组件 和 props 配合使用
:::details 案例 子组件修改父组件数据
import React, { createRef } from 'react';import { render } from 'react-dom';
class Parent extends React.Component { constructor() { super() this.inputRef1 = createRef() this.inputRef2 = createRef() // 父组件有张银行卡,两个儿子都可以存钱改变余额 this.state = { money: 10000 } } getFocus1 = () => { this.inputRef1.current.inRef1.current.focus(); } getFocus2 = () => { this.inputRef2.current.inRef2.current.focus(); } // 父亲提供 一个改变自己余额的方法 changeMoney = (x) => { this.setState({ money: this.state.money + x }) } render() { return <div> 父组件余额{this.state.money} <TextInput changeMoney={this.changeMoney} ref={this.inputRef1} /> <button onClick={this.getFocus1}>焦点一</button> <TextInput2 changeMoney={this.changeMoney} ref={this.inputRef2} /> <button onClick={this.getFocus2}>焦点二</button> </div> }}class TextInput extends React.Component { constructor() { super() this.inRef1 = createRef() } addMoney = () => { // 通过this.props,拿到父组件传过来的方法 let SonMoney = parseFloat(this.inRef1.current.value) this.props.changeMoney(SonMoney) } render() { return <> 我是input <input ref={this.inRef1} /> <button onClick={this.addMoney}>大儿子存钱</button> </> }}class TextInput2 extends React.Component { constructor() { super() this.inRef2 = createRef() } addMoney2 = () => { // 通过this.props,拿到父组件传过来的方法 let SonMoney = parseFloat(this.inRef2.current.value) this.props.changeMoney(SonMoney) } render() { return <> 我是第二个input <input ref={this.inRef2} /> <button onClick={this.addMoney2}>小儿子存钱</button> </> }}render(<Parent />, window.root);
:::
- useRef (函数组件) useref性能更好,因为useref是复用的老的对象。createRef 每次都会创建一个新的的对象。
function Parent() { function getFoucs() { childRef.current.focus() } let childRef = useRef() return <> <ForwardChild ref={childRef} /> <button onClick={getFoucs}>点击获取焦点</button> </>}
- 函数组件作为子组件,需要使用ref的时候需要外面包裹
forwardRef(Child)
例1
import React, { forwardRef, useRef } from 'react';import { render } from 'react-dom';function Parent() { function getFoucs() { childRef.current.focus() } let childRef = useRef() return <> <ForwardChild ref={childRef} /> <button onClick={getFoucs}>点击获取焦点</button> </>}// forwardChild 的ref 会通过forwardRef传递给childfunction Child(props, Pref) { // let refA = React.createRef(); return <> <input ref={Pref} /> </>;}let ForwardChild = forwardRef(Child)render(<Parent />, window.root);
例2
import React, { forwardRef } from 'react';import { render } from 'react-dom';export default class Parent extends React.Component { constructor() { super(); this.childref = React.createRef() } getFocus = () => { this.childref.current.focus(); console.log(this.childref); } render() { return (<div> <ForwardChild ref={this.childref} /> <button onClick={this.getFocus}>点击获取焦点</button> </div>) }}// forwardChild 的ref 会通过forwardRef传递给childfunction Child(props, Pref) { // let refA = React.createRef(); return <> <input ref={Pref} /> </>;}let ForwardChild = forwardRef(Child)render(<Parent />, window.root);
#
英文释义ref :reference
adj: 引用createRef
类组件用useRef
函数组件用??