ref转发及使用,forwardRef取消指向

ref转发:组件外部访问组件内部元素

一.方式:1.ref字符串:内部组件通过this.ref获取对应元素

   2.通过createRef创建ref对象的current属性获取对应元素(推荐)

二.使用:

   ref指向虚拟DOM,获取真实DOM

   ref指向组件,获取组件实例化对象, 二者只能指向一个

 第一步 creatRef创建ref对象

 第二步 将ref对象传递给组件 (不要用ref属性传递ref对象

 第三步 在组件中,将ref对象指向内部的虚拟DOM (ref对象只能指向类组件,不能指向函数组件)

三.forwardRef

  取消ref对象对组件的指向(包括类组件和函数组件)

  参数是回调函数

  回调函数参数 属性对象 ,被取消指向的ref对象

  返回值 渲染的组件

 ref指向类组件:

import React, {Component, createRef} from 'react';
import {render} from 'react-dom';

// 2在外部创建ref对象
let refObj = createRef();
class App extends Component { 
    // 组件创建完成
        // componentDidMount() {
        //     //1.内部通过this.refs访问
        //     this.refs.exp.style.color = 'red'
        // }
    render() {
       console.log(this.props);
        return (
            <div>
                {/* <h1 ref="exp">举例1</h1> */}
                {/*2 ref对象指向虚拟DOM,但直接使用外部ref对象 内部变量与外部变量耦合*/}
                {/* <h1 ref={refObj}>举例2</h1> */}
                {/*4 一旦指向组件App 内部就无法指向虚拟DOM,所以换一个名字*/}
                {/* <h1 ref={this.props.ref}>举例3</h1> */}
                {/*5 ref指向一个,指向多个会产生覆盖问题 后面覆盖前面 */}
                <h1 ref={this.props.refNew}>举例4</h1>
                <h1 ref={this.props.refNew}>举例5</h1>
                <h1>举例</h1>
            </div>
        )
    }
}
// 3.为避免发生2的耦合将ref对象传递,此时ref指向组件App
// render(<App ref={refObj}></App>, document.getElementById('app'), () => {
//     console.log('渲染完成',refObj);
//     // 在组件外部访问内部
//     // refObj.current.style.color = 'red';
// })
 /*解决方法: 让新的指向组件App, 让ref指向虚拟DOM即可 */
render(<App refNew={refObj}></App>, document.getElementById('app'), () => {
    console.log('渲染完成',refObj);
    // 在组件外部访问内部
    refObj.current.style.color = 'red';
})

 ref不能指向函数组件:

import React, {Component, createRef} from 'react';
import {render} from 'react-dom';
// 在外部创建ref对象
let refObj = createRef();
// 函数组件
function App(props) {
    console.log(props);
    return(
        <div>
            <h1>举例1</h1>
            <h1 ref={props.refNewT}>举例2</h1>
            {/* 同样不要重复使用 */}
            <h1 ref={props.refNewT}>举例3</h1>
        </div>
    )
}
// ref对象不能指向函数组件
// 报错Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?in App
// render(<App ref={refObj}></App>, app, () => {
//     console.log('render', refObj );
// })
render(<App refNewT={refObj}></App>, app, () => {
    console.log('render', refObj);
    // 组件外部访问组件内部的元素
    refObj.current.style.color = 'red';
})

 为了使ref能够指向函数组件React提供了forwardRef 函数组件的取消

import React, {Component, createRef, forwardRef} from 'react';
import {render} from 'react-dom';
// 在外部创建ref对象
let refObj = createRef();
// 函数组件
function App(props) {
    console.log(props);
    return(
        <div>
            <h1>举例1</h1>
            <h1 ref={props.refRep}>举例2</h1>
            {/* 同样不要重复使用 */}
            <h1 ref={props.refNewT}>举例3</h1>
        </div>
    )
}
let DealApp = forwardApp((props, ref) => {
    // 此时取消ref对象,要取消在App上的ref就要换一个名称让ref取消
    return <App {...props} refRep={ref} ></App>
})

// render(<App ref={refObj}></App>, app, () => {
//     console.log('render', refObj );
// })
render(<DealApp ref={refObj} msg='zihui'></DealApp>, app, () => {
    console.log('render', refObj );
    refObj.current.style.color = 'red';
})

类组件的取消:

import React, {Component, createRef, forwardRef} from 'react';
import {render} from 'react-dom';


let refObj = createRef();
class App extends Component { 
    render() {
       console.log(this.props);
        return (
            <div>
                <h1 ref={this.props.refRep}>举例1</h1>
                  // 同样不能重复
                <h1 ref={this.props.refRep}>举例2</h1>
                <h1>举例</h1>
            </div>
        )
    }
}
let DealApp = forwardRef((props, ref) => {
    // console.log(...args);
    return <App {...props} refRep={ref}></App>
})
// ref指向组件就不能指向虚拟DOM 所以取消指向组件App
// render(<App ref={refObj}></App>, document.getElementById('app'), () => {
//     console.log('渲染完成',refObj);
//     // 在组件外部访问内部
//     // refObj.current.style.color = 'red';
// })
render(<DealApp ref={refObj} num={100}></DealApp>, app, () => {
    console.log('渲染完成', refObj);
    refObj.current.style.color = 'red';
})

 高级组件中ref应用

import React, { Component, createRef, forwardRef } from 'react';
import { render } from 'react-dom';
console.log(React);

// 组件
class App extends Component {
    constructor(props) {
        super(props);
        // 状态
        this.state = {
            msg: ''
        }
        // 创建ref对象
        this.dom = createRef();
    }
    // 组件创建完成
    componentDidMount() {
        // console.log(this.dom);
        this.dom.current.style.color = 'red';
    }
    render() {
        let { msg } = this.state;
        return (
            <div>
                <input type="text" value={msg} onChange={e => this.setState({ msg: e.target.value })} />
                <hr />
                <HighCompDemo msg={msg} ref={this.dom}></HighCompDemo>
            </div>
        )
    }
}

class Demo extends Component {
    render() {
        // console.log(this.props, 222);
        return (
            <div>
                <h1 ref={this.props.HighCompRef}>demo: {this.props.msg}</h1>
            </div>
        )
    }
}
// 定义高阶函数不能修改原组件
function highComp(Comp) {
    // 定义新的组件
    class HighComp extends Component {
        // 修改的是新的包装组件,原组件不受影响
        // 监听属性的变化
        componentWillReceiveProps(props) {
            console.log(222, props);
        }
        render() {
            // console.log(this.props, 111);
            // 转发给原组件
            return <Comp {...this.props}></Comp>;
        }
    }
    // 返回新的组件
    // return HighComp;
    // 取消指向
    return forwardRef((props, ref) => <HighComp {...props} HighCompRef={ref}></HighComp>)
}

// 拓展高阶组件
let HighCompDemo = highComp(Demo);

render(<App></App>, app)

 

posted @ 2022-03-15 09:56  HaoyuSun  阅读(522)  评论(0)    收藏  举报