react(六)-- ref

本文详细介绍了React中ref的使用,包括受控组件与非受控组件的区别,以及ref的各种应用场景,如时间组件的更新、表单输入的收集与操作。还涵盖了ref-forward技术在父子组件间的应用和事件绑定技巧。
摘要由CSDN通过智能技术生成

component - ref

  1. 时钟案例
    (1)受控组件
<script type="text/babel">
        //受控组件
    class Clock extends React.Component {
        state = { time : new Date().toLocaleTimeString() }
        render() {
            return (
                <div>
                    <h2>{this.state.time}</h2>
                </div>
            )
        }
        componentDidMount() {
            setInterval(() => {
                this.setState({
                    time : new Date().toLocaleTimeString()
                })
            },1000)
        }
    }
    ReactDOM.render(<Clock />, document.getElementById("app"));
</script>

在这里插入图片描述

         (2)非受控组件1(string)

<script type="text/babel">
    //refs 引用容器
    // 01 找到真实DOM容器
    // this.refs = {}  // 这个对象容器 => 用来存储真实DOM的引用
    class Clock extends React.Component {          
        render() {
            return (
                <div>
                    {/*02 真实DOM放到this.refs={} 容器里
                      通过createElement 创建虚拟DOM,新增ref
                      ReactDOM.render 把虚拟DOM同步 渲染成真实DOM => 判断是否有ref
                      如果有ref:把ref属性对应的真实DOM h2 放进this.refs={}里面;
                      {ref属性对应的值 => key : 真实DOM h2} => {timeRef : 真实DOM h2}
                    */}
                    <h2 ref='timeRef'>{new Date().toLocaleTimeString()}</h2>
                </div>
            )
        }
        componentDidMount() {
            console.log(this.refs);
            setInterval(() => {             
                //03 this.refs={} 容器里获取真实DOM => h2 => 进行操作
                this.refs.timeRef.innerHTML = new Date().toLocaleTimeString()                  
            },1000)
        }
    }
    ReactDOM.render(<Clock />, document.getElementById("app"));
</script>

在这里插入图片描述

思考:

  • 该案例是:实例组件.refs = {key : 真实DOM} key为ref属性对应的值(timeRef)
  • 我们如何做到:实例组件.key = 真实DOM ?

         (3)非受控组件2(function)

<script type="text/babel">     
    class Clock extends React.Component {          
        render() {
            return (
                <div>
                    {/* 
                      通过createElement 创建虚拟DOM,新增ref属性
                      ReactDOM.render 把虚拟DOM同步 渲染成真实DOM => 判断是否有ref
                      如果有ref:判断ref属性对应的值是否为函数=>如果是:执行这个函数,把真实DOM作为参数传进去
                      组件实例.key = 真实DOM(element)
                    */}
                        
                    <h2 ref={e=>this.timeRef=e}>{new Date().toLocaleTimeString()}</h2>
                    <h2 ref={(element)=>{
                        this.timeRef2 = element
                    }}>{new Date().toLocaleTimeString()}</h2>
                </div>
            )
        }
        //组件挂载完毕:第一次渲染完毕 => 虚拟DOM已经完全转化成真实DOM
        componentDidMount() {
            console.log(this);
            console.log(this.refs);
            setInterval(() => {             
                // this.key = 真实DOM  h2 => 进行操作
                this.timeRef.innerHTML = new Date().toLocaleTimeString()   
                this.timeRef2.innerHTML = new Date().toLocaleTimeString()                   
            },1000)
        }
    }
    ReactDOM.render(<Clock />, document.getElementById("app"));
</script>

在这里插入图片描述
         (4)非受控组件3(createRefs)

源码分析:
an immutable object with a single mutable value

	function createRef() {
            var refObject = {
                current: null
            };
            {
                Object.seal(refObject); // 对参数对象进行封闭 不能添加新的属性,只能有一个属性current
            }
            return refObject;
        }

注意:

  • 执行React.createRef() => 返回值{current:null}对象容器,但是这个返回值对象源码没有挂载到组件实例上,所以需要我们手动挂载 this.key = React.createRef()
	<script type="text/babel">
        class Clock extends React.Component {      
            constructor(props){
                super(props)
                this.timeRef = React.createRef() // {current: null}
            }    
            render() {
                return (
                    <div>
                        {/*02 
                          通过createElement 创建虚拟DOM,新增ref属性
                          ReactDOM.render 把虚拟DOM同步 渲染成真实DOM => 判断是否有ref
                          如果有ref:会找到ref对应的值 => {current: null} 容器,把真实DOM h2 赋值给 容器current 属性
                          不需要给引用容器提供 key
                        */}
                        
                        <h2 ref={this.timeRef}>{new Date().toLocaleTimeString()}</h2>
                        
                    </div>
                )
            }
            //组件挂载完毕:第一次渲染完毕 => 虚拟DOM已经完全转化成真实DOM
            componentDidMount() {
                console.log(this);
                console.log(this.timeRef);
                setInterval(() => {             
                    //03 this.key.current = 真实DOM  h2 => 进行操作
                    this.timeRef.current.innerHTML = new Date().toLocaleTimeString()                  
                },1000)
            }
        }
        ReactDOM.render(<Clock />, document.getElementById("app"));
    </script>

在这里插入图片描述

三种方案总结:

  • ref = ‘key’ => this.refs = {} => {key : true DOM}
  • ref = {e=>this.key = e} => this.key = true DOM
  • this.key = React.createRef(); {current:null} = {current : true DOM}
  1. ref-form (form表单收集)
    (1)ref = ‘key’
    <script type="text/babel">
        class Form extends React.Component {      
            handleClick = ()=>{
                console.log(this.refs);
                console.log(this.refs.inputRef);
                console.log(this.refs.inputRef.value);
            }
            render() {
                return (
                    <div>
                        <input type="text" ref='inputRef' />
                        <button onClick={this.handleClick}>commit</button>
                    </div>
                )
            }
        }
        ReactDOM.render(<Form />, document.getElementById("app"));
    </script>

在这里插入图片描述
         (2)ref = {e=>this.属性 = e}

	<script type="text/babel">
        class Form extends React.Component {      
            handleClick = ()=>{
                console.log(this.inputRef);
                console.log(this.inputRef.value);
            }
            render() {
                return (
                    <div>
                        <input type="text" ref={e=>this.inputRef = e} />
                        <button onClick={this.handleClick}>commit</button>
                    </div>
                )
            }
        }
        ReactDOM.render(<Form />, document.getElementById("app"));
    </script>

在这里插入图片描述
         (3)ref = {this.属性}

	<script type="text/babel">
        class Form extends React.Component {    
            constructor(){
                super()
                this.inputRef = React.createRef()
            }  
            handleClick = ()=>{
                console.log(this.inputRef);
                console.log(this.inputRef.current);
                console.log(this.inputRef.current.value);
            }
            render() {
                return (
                    <div>
                        <input type="text" ref={this.inputRef} />
                        <button onClick={this.handleClick}>commit</button>
                    </div>
                )
            }
        }
        ReactDOM.render(<Form />, document.getElementById("app"));
    </script>

在这里插入图片描述
         (4)绑定事件

	<script type="text/babel">
        class Form extends React.Component {    
            handleChange = (e)=>{
                console.log(e.target.value);
            }
            render() {
                return (
                    <div>
                        <input type="text" onChange={this.handleChange} />
                    </div>
                )
            }
        }
        ReactDOM.render(<Form />, document.getElementById("app"));
    </script>

在这里插入图片描述

3.form 案例

  • 失去焦点 => 触发事件 => 弹出input value
<script type="text/babel">
    //失去焦点 => 触发事件 => 弹出input value
    class Form extends React.Component {    
         handleBlur = (e)=>{
            console.log(e.target)
            console.log(e.target.value);
            alert(e.target.value)
         }
         render() {
             return (
                <div>
                    <input type="text" onBlur={this.handleBlur} />
                    <button onClick={this.handleClick}>commit</button>
                </div>
            )
         }
    }
    ReactDOM.render(<Form />, document.getElementById("app"));
</script>

在这里插入图片描述

  • 点击 => 触发事件 => 弹出input value
<script type="text/babel">    
        class Form extends React.Component {    
            constructor() {
                super()
                this.inputRef =React.createRef()
            }
            handleClick = ()=>{
                alert(this.inputRef.current.value)
            }
            render() {
                return (
                    <div>
                        <input type="text" ref={this.inputRef} />
                        <button onClick={this.handleClick}>commit</button>
                    </div>
                )
            }
        }
        ReactDOM.render(<Form />, document.getElementById("app"));
    </script>

在这里插入图片描述

  • 获取焦点
<script type="text/babel">      
    class Form extends React.Component {    
        constructor() {
            super()
            this.inputRef =React.createRef()
        }
        handleClick = ()=>{
            // 点击按钮获取焦点
            this.inputRef.current.focus()
        }
        render() {
            return (
                <div>
                    <input type="text" ref={this.inputRef} />
                    <button onClick={this.handleClick}>commit</button>
                </div>
            )
        }
        //已经渲染完毕 可以直接使用真实DOM
        componentDidMount() {
            //自动获取焦点
            this.inputRef.current.focus()
        }
    }
    ReactDOM.render(<Form />, document.getElementById("app"));
</script>

4.ref-forward

  • 类组件:
<script type='text/babel'>
    class ChildInput extends React.Component {
        render() {
            return (
                <div>
                    <h2>child input</h2>
                    <input type="text" ref={this.props.callbackRef} />
                </div>
            )
        }
    }
    // 需求:获取某个子组件里面的 具体某个DOM
    // 回调函数方式:给子组件传递一个回调函数callback,子组件通过ref = {callback},把组件的具体DOM挂载到父组件属性
    class FatherForm extends React.Component {
    
        callbackRef = (e) => {
            this.inputRef = e
        }

        handleClick = () => {
            console.log(this);
            this.inputRef.focus()
        }

        render() {
            return (
                <div>
                    <ChildInput callbackRef={this.callbackRef} />
                    <button onClick={this.handleClick}>commit</button>
                </div>
            )
        }
    }
    ReactDOM.render(<FatherForm />, document.getElementById('app'))
</script>

在这里插入图片描述

  • 函数组件:
<script type='text/babel'>
    function ChildInput (props) {
        return (
            <div>
                <h2>child input</h2>
                <input type="text" ref={props.callbackRef} />
            </div>
        )
    }

    class FatherForm extends React.Component {
    
        callbackRef = (e) => {
            this.inputRef = e
        }

        handleClick = () => {
            console.log(this);
            this.inputRef.focus()
        }

        render() {
            return (
                <div>
                    <ChildInput callbackRef={this.callbackRef} />
                    <button onClick={this.handleClick}>commit</button>
                </div>
            )
        }
    }
    ReactDOM.render(<FatherForm />, document.getElementById('app'))
</script>

在这里插入图片描述

  • forward(转发)方式
<script type='text/babel'>
    function ChildInput(props ,ref) {
        return (
            <div>
                <h2>child input</h2>
                <input type="text" ref={ref} /> {/*地址 => {current:null} => {current:input}*/}
            </div>
        )
    }
    // 引用转发:引用地址的转发,自动传递ref的一种技术
    const RefChildInput = React.forwardRef(ChildInput)
    class FatherForm extends React.Component {
        constructor() {
            super()
            this.inputRef = React.createRef()
        }
        callbackRef = (e) => {
            this.inputRef = e
        }
        handleClick = () => {
            console.log(this);
            this.inputRef.current.focus()
        }
        render() {
            return (
                <div>
                    <RefChildInput ref={this.inputRef} />
                    <button onClick={this.handleClick}>commit</button>
                </div>
            )
        }
    }
    ReactDOM.render(<FatherForm />, document.getElementById('app'))
</script>

在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值