react中使用ref和useImperativeHandle

197 阅读2分钟

react中使用ref和useImperativeHandle

1.使用ref

  • useRef只能在函数组件中使用
  • createRef既可以在函数中使用 也可以在类函数中使用
let prev1,
    prev2;
const Demo = function Demo() {
    let [num, setNum] = useState(0);

    //分别使用useRef和createRef
    let box1 = useRef(null),
        box2 = React.createRef();
    if (!prev1) {
        // 第一次DEMO执行,把第一次创建的REF对象赋值给变量
        prev1 = box1;
        prev2 = box2;
    } else {
        // 第二次DEMO执行,我们验证一下,新创建的REF对象,和之前第一次创建的REF对象,是否一致?
        console.log(prev1 === box1); //true  useRef再每一次组件更新的时候(函数重新执行),再次执行useRef方法的时候,不会创建新的REF对象了,获取到的还是第一次创建的那个REF对象!!
        console.log(prev2 === box2); //false createRef在每一次组件更新的时候,都会创建一个全新的REF对象出来,比较浪费性能!!
        // 总结:在类组件中,创建REF对象,我们基于 React.createRef 处理;但是在函数组件中,为了保证性能,我们应该使用专属的 useRef 处理!!
    }

    useEffect(() => {
        console.log(box1.current);  // <span className="num" >1</span>
        console.log(box2.current);  // <span className="num">哈哈哈</span>
    });

    return <div className="demo">
        <span className="num" ref={box1}>{num}</span>
        <span className="num" ref={box2}>哈哈哈</span>
        <Button type="primary" size="small"
            onClick={() => {
                setNum(num + 1);
            }}>
            新增
        </Button>
    </div>;
};

2.使用useImperativeHandle

// 基于ref获取子组件的实例,这样基于实例,可以调用子组件内部,挂载到实例上的东西
class Child extends React.Component {
    state = { x: 1000 };
    render() {
        return <div className="child-box">
            {this.state.x}
        </div>;
    }
} 

  // 1.forwardRef的使用
 // 基于forwardRef实现ref转发,目的:获取子组件内部的某个元素
const Child = React.forwardRef(function Child(props, ref) {
    // console.log(ref); //在DEMO中,调用Child的时候,传递的ref对象「x」
    return <div className="child-box">
        <span ref={ref}>哈哈哈</span>
    </div>;
}); 


// 函数子组件内部,可以有自己的状态和方法了;如何实现:基于forwardRef实现ref转发的同时,获取函数子组件内部的状态或者方法呢? => useImperativeHandle
// 2.useImperativeHandle的使用
const Child = React.forwardRef(function Child(props, ref) {
    let [text, setText] = useState('你好世界');
    const submit = () => { };

    useImperativeHandle(ref, () => {
        // 在这里返回的内容,都可以被父组件的REF对象获取到
        return {
            text,
            submit
        };
    });

    return <div className="child-box">
        <span>哈哈哈</span>
    </div>;
});

const Demo = function Demo() {
    let x = useRef(null);
    useEffect(() => {
        console.log(x.current);
    }, []);

    return <div className="demo">
       //将创建的ref传给子组件
        <Child ref={x} />  
    </div>;
};