forwardRef
API(与
useImperativeHandle
钩子配合使用)允许你自定义如何以及在哪里放置你的refs在你的自定义组件中。此外,
forwardRef
是将ref传递给你的自定义函数组件的唯一方法。
首先,理解refs在类组件、函数组件和常规DOM元素上的工作方式不同,这很重要。
从
文档中可以看到:
引用值因节点类型的不同而异:
1. 当在HTML元素上使用ref属性时,使用React.createRef()在构造函数中创建的ref会将底层DOM元素作为其当前属性。
2. 当在自定义类组件上使用ref属性时,ref对象将获得组件的已挂载实例作为其当前属性。
3. 不能在函数组件上使用ref属性,因为它们没有实例。
以下是在不同元素类型上使用refs的示例:
1. 在DOM元素上使用ref会给你一个对DOM节点本身的引用:
function AutoFocusInput() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus();
}, []);
return <input ref={inputRef} />
}
2. 通过在类组件上使用ref,我们可以访问该实例及其所有方法和字段:
class Child extends Component {
state = {color: "red"}
toggleColor = () => this.setState({color: this.state.color === "red" ? "blue" : "red"})
render() {
return <div style={{backgroundColor: this.state.color}}>yo</div>
}
}
class Parent extends Component {
childRef = createRef();
handleButtonClicked = () => {
this.childRef.current.toggleColor();
}
render() {
return (
<div>
<button onClick={this.handleButtonClicked}>toggle color!</button>
<Child ref={childRef} />
</div>
);
}
}
3. 现在,最终回答你的问题。Refs不能被传递给函数组件,因为它们没有实例!
唯一的方法是使用forwardRef来将ref传递给函数组件。当使用forwardRef时,你可以简单地将ref传递给DOM元素,这样父组件就可以像示例1中那样访问它,或者你可以使用useImperativeHandle钩子创建一个具有字段和方法的对象,这类似于示例2。
3.1 将ref简单地传递给DOM元素:
const RedInput = forwardRef((props, ref) => {
return <input style={{color: "red"}} {...props} ref={ref} />
});
function AutoFocusInput() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus();
}, []);
return <RedInput ref={inputRef} />
}
3.2 将父引用附加到自定义对象:
如果您想像处理类组件实例那样将函数或字段附加到引用,请使用`useImperativeHandle`钩子:
const Child = forwardRef((props, ref) => {
const [color, setColor] = useState("red");
useImperativeHandle(ref, () => ({
toggleColor: () => setColor(prevColor => prevColor === "red" ? "blue" : "red")
}));
return <div style={{backgroundColor: color}}>yo</div>;
});
class Parent extends Component {
childRef = createRef();
handleButtonClicked = () => {
this.childRef.current.toggleColor();
}
render() {
return (
<div>
<button onClick={this.handleButtonClicked}>toggle color!</button>
<Child ref={childRef} />
</div>
);
}
}
forwardRef
的不同方式。 - deckele