有時候會希望可以不透過state、props傳遞的方式呼叫child component內部的function,這種方式稱為imperative approach。
以下示範如何用 ref、forwardRef 和 useImperativeHandle hook 達成:
// Form.js (parent component)
import {useState, useRef} from 'react'
export default function Form(){
    const [emailIsValid, setEmailIsValid] = useState(false);
    const [passwordIsValid, setPasswordIsValid] = useState(false);
    const emailRef = useRef();
    const passwordRef = useRef();
    // * Call focus function (alias: activate) inside <Input/>
    useEffect(()=>{
        if(!emailIsValid){
            emailRef.current.activate();   // *
        } else{
            passwordRef.current.activate();   // *
        }
    }, []);
    return (
        <form>
            <Input
                ref={emailRef}
                id="email"
                name="email"
                type="text"
            >
            <Input
                ref={passwordRef}
                id="password"
                name="password"
                type="password"
            >
        </form>
    );
}
<Input> 實際上是一個用來包裝 <label> 和 <input> 標籤的component:
// Input.js (child component)
import { useRef, useImperativeHandle } from 'react'
// ref is the ref defined outside and "actually" used via fowardRef
export default function React.forwardRef(Input(props, ref){
    const inputRef = useRef();
    const focus = () => {
        inputRef.current.focus();
    }
    // Manipulate something inside imperatively
    // (NOT through regular state or props management)
    useImperativeHandle(ref, () => {
        return {
            // A translation object that let something that can be used outside
            activate: focus
        }
    });
    return (
        <>
            <label>{props.name}</label>
            <input
                ref={inputRef}   // Ref defined inside
                id={props.id}
                name={props.name}
                type={props.type}
            >
        </>
    );
});
重點
- Imperative approach 要用 useImperativeHandlehook;
- useImperativeHandle的第一個引數是定義在parent component的ref (e.g., emailRef、passwordRed),第二個引數則要傳入一個function並return一個特別的object,這個object可以放一些要被parent component使用的東西,如範例中的focus函式可以透過- activate名稱呼叫;
- 外部ref並非props的一部分,要額外跟props一起傳入,如範例中(props, ref)的ref;
- 此外,要真正能使用外部ref,必須將child component用 forwardRef包起來,forwardRef會綁定外部ref並回傳一個component。
 
References
React - The Complete Guide (incl Hooks, React Router, Redux)
![[day08] Closure & Private:番外短篇 隱私成員](https://static.coderbridge.com/images/covers/default-post-cover-1.jpg)

