forwardRef
forwardRef γ―γθ¦ͺγ³γ³γγΌγγ³γγ«ε―Ύγγ¦ DOM γγΌγγ ref γ¨γγ¦ε
¬ιγ§γγγγγ«γγΎγγ
const SomeComponent = forwardRef(render)γͺγγ‘γ¬γ³γΉ
forwardRef(render)
forwardRef() γεΌγ³εΊγγγ¨γ§γγ³γ³γγΌγγ³γγ ref γεγεγ£γ¦γγγεγ³γ³γγΌγγ³γγ«θ»’ι (forward) γ§γγγγγ«γͺγγΎγγ
import { forwardRef } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
// ...
});εΌζ°
render: γ³γ³γγΌγγ³γοΏ½?γ¬γ³γγΌι’ζ°γ§γγReact γ―γοΏ½?ι’ζ°γθ¦ͺγγεγεγ£γ props γγγ³refγ¨γ¨γγ«εΌγ³εΊγγΎγγθΏγ JSX γγ³γ³γγΌγγ³γοΏ½?εΊεγ¨γͺγγΎγγ
θΏγε€
forwardRef γ― JSX γ§γ¬γ³γγΌγ§γγ React γ³γ³γγΌγγ³γγθΏγγΎγγγγ¬γΌγ³γͺι’ζ°γ¨γγ¦οΏ½?οΏ½ηΎ©γγγ React γ³γ³γγΌγγ³γγ¨γ―η°γͺγγforwardRef γ«γγ£γ¦θΏγγγγ³γ³γγΌγγ³γγ― ref ε±ζ§γεγεγγγ¨γγ§γγΎγγ
注ζηΉ
- Strict Mode γ§γ―γReact γ―γ¬γ³γγΌι’ζ°γθͺ€γ£γ¦η΄ι’ζ°γ§γͺγγͺγ£γ¦γγΎγει‘γθ¦γ€γγγγγγγγγγ¬γ³γγΌι’ζ°γ 2 εεΌγ³εΊγγΎγγγγγ―ιηΊη°ε’ε°η¨οΏ½?ζεγ§γγγζ¬ηͺη°ε’γ«γ―ε½±ιΏγγΎγγγγ¬γ³γγΌι’ζ°γη΄η²γ§γγε ΄εοΌγγγ§γγγΉγγ§γοΌγγγγ―γ³γ³γγΌγγ³γοΏ½?γγΈγγ―γ«ε½±ιΏγδΈγγΎγγγεΌγ³εΊγοΏ½?γγ‘οΏ½?δΈζΉγγοΏ½?η΅ζγ―η‘θ¦γγγΎγγ
render ι’ζ°
forwardRef γ―εΌζ°γ¨γγ¦γ¬γ³γγΌι’ζ°γεγεγγΎγγReact γ―γοΏ½?ι’ζ°γ props γγγ³ ref γ¨γ¨γγ«εΌγ³εΊγγΎγγ
const MyInput = forwardRef(function MyInput(props, ref) {
return (
<label>
{props.label}
<input ref={ref} />
</label>
);
});εΌζ°
-
props: θ¦ͺγ³γ³γγΌγγ³γγγζΈ‘γγγ props γ§γγ -
ref: θ¦ͺγ³γ³γγΌγγ³γγγζΈ‘γγγrefε±ζ§γ§γγrefγ―γͺγγΈγ§γ―γοΏ½?ε ΄εγ¨ι’ζ°οΏ½?ε ΄εγγγγΎγγθ¦ͺγ³γ³γγΌγγ³γγ ref γζΈ‘γγ¦γγͺγε ΄εγ―nullγ«γͺγγΎγγεγεγ£γrefγ―γε₯οΏ½?γ³γ³γγΌγγ³γγ«ζΈ‘γγγuseImperativeHandleγ«ζΈ‘γγΎγγ
θΏγε€
forwardRef γ― JSX γ§γ¬γ³γγΌγ§γγ React γ³γ³γγΌγγ³γγθΏγγΎγγγγ¬γΌγ³γͺι’ζ°γ¨γγ¦οΏ½?οΏ½ηΎ©γγγ React γ³γ³γγΌγγ³γγ¨γ―η°γͺγγforwardRef γ«γγ£γ¦θΏγγγγ³γ³γγΌγγ³γγ― ref ε±ζ§γεγεγγγ¨γγ§γγΎγγ
δ½Ώη¨ζ³
θ¦ͺγ³γ³γγΌγγ³γγ« DOM γγΌγγε ¬ιγγ
γγγ©γ«γγ§γ―γεγ³γ³γγΌγγ³γε
οΏ½? DOM γγΌγγ―γγ©γ€γγΌγγ§γγγγγγζγ«γ―θ¦ͺγ« DOM γγΌγγε
¬ιγγγγ¨γζη¨γͺε ΄εγγγγΎγγδΎγγ°γγγΌγγ«γγ©γΌγ«γΉγε½γ¦γγγ¨γ許ε―γγγε ΄εγ§γγγγγζη€Ίηγ«θ¨±ε―γγγγγ«γγ³γ³γγΌγγ³γοΏ½?οΏ½ηΎ©γ forwardRef() γ§γ©γγγγΎγγ
import { forwardRef } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
const { label, ...otherProps } = props;
return (
<label>
{label}
<input {...otherProps} />
</label>
);
});props οΏ½?εΎοΏ½?第 2 εΌζ°γ¨γγ¦ ref γζΈ‘γγγΎγγε ¬ιγγγ DOM γγΌγγ«γγγζΈ‘γγ¦γγ γγγ
import { forwardRef } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
const { label, ...otherProps } = props;
return (
<label>
{label}
<input {...otherProps} ref={ref} />
</label>
);
});γγγ§γθ¦ͺοΏ½? Form γ³γ³γγΌγγ³γγγMyInput γ«γγ£γ¦ε
¬ιγγγ <input> DOM γγΌγγ«γ’γ―γ»γΉγ§γγγγγ«γͺγγΎγγ
function Form() {
const ref = useRef(null);
function handleClick() {
ref.current.focus();
}
return (
<form>
<MyInput label="Enter your name:" ref={ref} />
<button type="button" onClick={handleClick}>
Edit
</button>
</form>
);
}γοΏ½? Form γ³γ³γγΌγγ³γγ― MyInput γ« ref γζΈ‘γγ¦γγΎγγMyInput γ³γ³γγΌγγ³γγ―γοΏ½? ref γγγ©γ¦γΆοΏ½? <input> γΏγ°γ«θ»’ιγγ¦γγΎγγγοΏ½?η΅ζγForm γ³γ³γγΌγγ³γγ―γοΏ½? <input> DOM γγΌγγ«γ’γ―γ»γΉγγfocus() γεΌγ³εΊγγγ¨γγ§γγγγγ«γͺγγΎγγ
γ³γ³γγΌγγ³γε οΏ½? DOM γγΌγγΈοΏ½? ref γε ¬ιγγγγ¨γ§γεΎγ§γ³γ³γγΌγγ³γοΏ½?ε ι¨γε€ζ΄γγοΏ½?γι£γγγͺγγγ¨γ«ζ³¨ζγγ¦γγ γγγιεΈΈγ―γγγΏγ³γγγγΉγε ₯εγγ£γΌγ«γγͺγ©οΏ½?εε©η¨ε―θ½γͺδ½γ¬γγ«γ³γ³γγΌγγ³γγγγ― DOM γγΌγοΏ½?ε ¬ιγθ‘γγΎγγγγ’γγΏγΌγγ³γ‘γ³γοΏ½?γγγͺγ’γγͺγ±γΌγ·γ§γ³γ¬γγ«οΏ½?γ³γ³γγΌγγ³γγ§γ―θ‘γγΎγγγ
δΎ 1/2: γγγΉγε
₯εγγ£γΌγ«γγ«γγ©γΌγ«γΉ
γγΏγ³γγ―γͺγγ―γγγ¨γε
₯εγγ£γΌγ«γγ«γγ©γΌγ«γΉγε½γ¦γγγΎγγForm γ³γ³γγΌγγ³γγ― ref γοΏ½?οΏ½ηΎ©γγγγγ MyInput γ³γ³γγΌγγ³γγ«ζΈ‘γγΎγγMyInput γ³γ³γγΌγγ³γγ―γοΏ½? ref γγγ©γ¦γΆοΏ½? <input> γ«θ»’ιγγΎγγγγγ«γγγForm γ³γ³γγΌγγ³γγ― <input> γ«γγ©γΌγ«γΉγε½γ¦γγγγγγ«γͺγγΎγγ
import { useRef } from 'react'; import MyInput from './MyInput.js'; export default function Form() { const ref = useRef(null); function handleClick() { ref.current.focus(); } return ( <form> <MyInput label="Enter your name:" ref={ref} /> <button type="button" onClick={handleClick}> Edit </button> </form> ); }
θ€ζ°γ³γ³γγΌγγ³γγη΅η±γγ ref οΏ½?θ»’ι
ref γ DOM γγΌγγ«θ»’ιγγ代γγγ«γη¬θͺγ³γ³γγΌγγ³γγ§γγ MyInput γ«θ»’ιγγγγ¨γγ§γγΎγγ
const FormField = forwardRef(function FormField(props, ref) {
// ...
return (
<>
<MyInput ref={ref} />
...
</>
);
});γγγ«γοΏ½? MyInput γ³γ³γγΌγγ³γγθͺθΊ«οΏ½? <input> γ« ref γθ»’ιγγγ°γFormField γΈοΏ½? ref γ―γοΏ½? <input> γΈοΏ½?εη
§γεγεγγγ¨γ«γͺγγΎγγ
function Form() {
const ref = useRef(null);
function handleClick() {
ref.current.focus();
}
return (
<form>
<FormField label="Enter your name:" ref={ref} isRequired={true} />
<button type="button" onClick={handleClick}>
Edit
</button>
</form>
);
}Form γ³γ³γγΌγγ³γγ― ref γοΏ½?οΏ½ηΎ©γγγγγ FormField γ«ζΈ‘γγ¦γγΎγγFormField γ³γ³γγΌγγ³γγ―γοΏ½? ref γ MyInput γ«θ»’ιγγMyInput γ―γγγγγ©γ¦γΆοΏ½? <input> DOM γγΌγγ«θ»’ιγγ¦γγΎγγγγγ§ Form γ DOM γγΌγγ«γ’γ―γ»γΉγ§γγγγγ«γͺγγΎγγ
import { useRef } from 'react'; import FormField from './FormField.js'; export default function Form() { const ref = useRef(null); function handleClick() { ref.current.focus(); } return ( <form> <FormField label="Enter your name:" ref={ref} isRequired={true} /> <button type="button" onClick={handleClick}> Edit </button> </form> ); }
DOM γγΌγοΏ½?代γγγ«ε½δ»€εγγ³γγ«γε ¬ιγγ
DOM γγΌγγγΎγγγ¨ε ¬ιγγ代γγγ«γδ½Ώη¨γ§γγγ‘γ½γγγεΆιγγγ«γΉγΏγ γͺγγΈγ§γ―γγ§γγγε½δ»€εγγ³γγ« (imperative handle) γε ¬ιγγγγ¨γγ§γγΎγγγγγθ‘γγ«γ―γDOM γγΌγγδΏζγγγγοΏ½?ε₯οΏ½? ref γοΏ½?οΏ½ηΎ©γγΎγγ
const MyInput = forwardRef(function MyInput(props, ref) {
const inputRef = useRef(null);
// ...
return <input {...props} ref={inputRef} />;
});γγγ¦εγεγ£γ ref γ useImperativeHandle γ«ζΈ‘γγref γ§ε
¬ιγγγε€γζοΏ½?οΏ½γγΎγγ
import { forwardRef, useRef, useImperativeHandle } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
const inputRef = useRef(null);
useImperativeHandle(ref, () => {
return {
focus() {
inputRef.current.focus();
},
scrollIntoView() {
inputRef.current.scrollIntoView();
},
};
}, []);
return <input {...props} ref={inputRef} />;
});δ½γγοΏ½?γ³γ³γγΌγγ³γγ MyInput γΈοΏ½? ref γεεΎγγγ¨γDOM γγΌγοΏ½?代γγγ«γγͺγγζΈγγ { focus, scrollIntoView } γ¨γγγͺγγΈγ§γ―γγεγεγγΎγγγγγ«γγγDOM γγΌγγ«γ€γγ¦ε
¬ιγγζ
ε ±γζε°ιγ«εΆιγγγγ¨γγ§γγΎγγ
import { useRef } from 'react'; import MyInput from './MyInput.js'; export default function Form() { const ref = useRef(null); function handleClick() { ref.current.focus(); // This won't work because the DOM node isn't exposed: // ref.current.style.opacity = 0.5; } return ( <form> <MyInput placeholder="Enter your name" ref={ref} /> <button type="button" onClick={handleClick}> Edit </button> </form> ); }
ε½δ»€εγγ³γγ«οΏ½?δ½Ώη¨γ«γ€γγ¦θ©³γγθͺγ
γγ©γγ«γ·γ₯γΌγγ£γ³γ°
γ³γ³γγΌγγ³γγ forwardRef γ§γ©γγγγ¦γγοΏ½?γ«γref γεΈΈγ« null γ«γͺγ
γγγ―ιεΈΈγεγεγ£γ ref γοΏ½?οΏ½ιγ«δ½Ώη¨γγοΏ½?γεΏγγ¦γγγγ¨γζε³γγΎγγ
δΎγγ°γγοΏ½?γ³γ³γγΌγγ³γγ― ref γε
¨γδ½Ώη¨γγ¦γγΎγγοΌ
const MyInput = forwardRef(function MyInput({ label }, ref) {
return (
<label>
{label}
<input />
</label>
);
});οΏ½?ζ£γγγ«γ―γοΏ½? ref γγDOM γγΌγγγref γεγε
₯γγγγ¨γγ§γγε₯οΏ½?γ³γ³γγΌγγ³γγ«ζΈ‘γγΎγγ
const MyInput = forwardRef(function MyInput({ label }, ref) {
return (
<label>
{label}
<input ref={ref} />
</label>
);
});δΈι¨οΏ½?γγΈγγ―γζ‘δ»Άδ»γγ§γγε ΄εγ«γγMyInput γΈοΏ½? ref γ null γ«γͺγγγ¨γγγγΎγγ
const MyInput = forwardRef(function MyInput({ label, showInput }, ref) {
return (
<label>
{label}
{showInput && <input ref={ref} />}
</label>
);
});showInput γ false οΏ½?ε ΄εγref γ―γ©οΏ½?γγΌγγ«γθ»’ιγγγͺγγγγMyInput γΈοΏ½? ref γ―η©ΊοΏ½?γΎγΎγ«γͺγγΎγγηΉγ«γδ»₯δΈοΏ½?δΎοΏ½?γγγ«ζ‘δ»Άγε₯οΏ½?γ³γ³γγΌγγ³γγδΎγγ° Panel οΏ½?δΈγ«ι γγγ¦γγε ΄εγγγγθ¦θ½γ¨γγγ‘γ§γγ
const MyInput = forwardRef(function MyInput({ label, showInput }, ref) {
return (
<label>
{label}
<Panel isExpanded={showInput}>
<input ref={ref} />
</Panel>
</label>
);
});