Ref in React

some little tech note about React and AntD

Let's talk a little about ref

  • basic usage example, we refer to the Dom. we prefer the sample1
// in ts
const refSample1 = React.useRef<HTMLDivElement>();
const refSample2 = React.useRef<HTMLDivElement|null>();

render(){
    return (
        <>
            <div ref={refSample1}>
                Hello I am div element
            </div>
            <div ref = {node=>{refSample2.current = node;}}>
                Hello I am div element2
            </div>
        </>
    )
}
  • customized Ref, ref is not only a dom, see this example
//ts
interface SampleRefProps{
    onClick:()=>void,
    wrapperElement:HTMLDivElement,
}
// in component1
const SampleComponent:React.RefForwardingComponent<SampleRefProps,any>=
    (props,ref)=>{
        const divRef = React.uesRef<HTMLDivElement>();
        React.useImperativeHandle(ref,()=>({
            onClick:()=>{console.log('hello click')},
            wrapperElement:divRef.current,
        }));
    
    return (
        <>
        <div ref = {divRef}>Hello I am body</div>
        </>
    )
}
// in Component2
const Demo:React.FC = ()=>{
    const ref = React.useRef<SampleRefProps>();
    return (
        <SampleComponent ref = {ref}/>
    )
}

  • When ref.current will be updated?
    according to the offical documents refs updates Before ComponentDidMount or ComponentDidUpdate or ComponentDidUnmount, that is straightforward for Class component, but for function component, I believe it will be updated after function execution but, before React.Effects() or React.LayoutEffects().
    • I just give a summary here, for function component, the order is render > React.useImperativeHandle > useLayoutEffect > useEffect (This is parallel with Browser repaint). Bellow is a code snappit
interface RefProps{
    element:HTMLDivElement|HTMLSpanElement|null;
};

const RefFC=React.forwardRef<RefProps,{isdiv:boolean}>(({isdiv=true},ref)=>{
    const domRef = React.useRef<HTMLSpanElement|HTMLDivElement>(null);
    // here just for demo, we can attach ref to dom directlly
    React.useImperativeHandle(ref,()=>{
        console.log(`useImperativeHandle executed`)
        return {
            element:domRef.current,
        };        
    })
    React.useEffect(()=>{
        console.log('effect of RefFC execution');
    })
    console.log(`befrore redner execution of RefFC`);
    return (
        <>
        {
            isdiv&&<div ref={domRef as any}>Hello I am div</div>
        }
        {
            !isdiv&&<span ref={domRef as any}>Hello I am span</span>
        }
        </>
    );
})

const RefDemo:React.FC=()=>{
    const refSample1 = React.useRef<HTMLDivElement>(null);
    const refSample2 = React.useRef<RefProps>(null);
    const [isdiv,setIsdiv]=React.useState<boolean>(true);
    React.useEffect(()=>{
        console.log(`This is Effect,refSample1 ${refSample1.current}`);
        console.log(`This is Effect,refSample2 ${refSample2.current?.element}`);
    });
    React.useLayoutEffect(()=>{
        console.log(`This is LayoutEffect:refSample1 ${refSample1.current}`);
        console.log(`This is LayoutEffect: refSample2: ${refSample2.current?.element}`)
    })

    console.log(`Before RefDemo Render return, refsample1 ${refSample1.current}`);
    console.log(`Before RefDemo Render return, refsample2 ${refSample2.current?.element}`);
    return (
        <>
        <div className="each-example">
            <h2>Check console, it will illustrate when ref will be populated and updated</h2>
            <p>For Functional Component, it will be updated after render and before Effect and Layout Effect</p>
            <div ref={refSample1}>
                Hello I am Body  refSample1
            </div>
            <div>
                <Button onClick={()=>setIsdiv(pre=>!pre)}>Click to Switch between div and span</Button>
            </div>
            <p>Bellow is refSample2</p>
            <RefFC ref ={refSample2} isdiv={isdiv}/>
            <p>
                In Conslusion, for function component ref, is populated or updated after function return, but before Effect and layoutEffect.
            </p>
        </div>
        </>
    );
}

Let's talk about the React.forwardRef<RefProps,Props>() and React.ForwardRefRenderFunction<RefProps,Props> type

lange is cheap, let's see the code. See, React.ForwardRefRenderFunction is the parameter type of forwardRef funciton.

function forwardRef<T, P = {}>(render: ForwardRefRenderFunction<T, P>): ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>>;
posted @ 2021-06-02 13:12  kongshu  阅读(66)  评论(0编辑  收藏  举报