Javascript 如何在React中使用forwardRef()?
我当前在我的React应用程序中收到以下错误: 无法为功能组件提供引用。尝试访问此引用 将失败。您是想使用React.forwardRef()吗 如何使用forwardRef()修复此问题 我的代码如下:Javascript 如何在React中使用forwardRef()?,javascript,reactjs,ref,Javascript,Reactjs,Ref,我当前在我的React应用程序中收到以下错误: 无法为功能组件提供引用。尝试访问此引用 将失败。您是想使用React.forwardRef()吗 如何使用forwardRef()修复此问题 我的代码如下: const Services: FunctionComponent = (): ReactElement => { const servicesRef = useRef(null); return ( <Layout> <ServicesL
const Services: FunctionComponent = (): ReactElement => {
const servicesRef = useRef(null);
return (
<Layout>
<ServicesList ref={servicesRef} />
</Layout>
);
};
export default Services;
const ServicesList: React.FunctionComponent = ({ children }: Props) => {
return (
<section className="my-24 md:my-32">
{children && children}
</section>
);
};
export default ServicesList;
const服务:FunctionComponent=():ReactElement=>{
const servicesRef=useRef(null);
返回(
);
};
出口默认服务;
const ServicesList:React.FunctionComponent=({children}:Props)=>{
返回(
{children&&children}
);
};
导出默认服务列表;
很好地解释
使用React.forwardRef包装组件,并将ref设置为预期的DOM元素
const FancyButton=React.forwardRef((props,ref)=>(
{props.children}
)
); 使用
forwardRef
api(再加上useImperialiveHandle
hook)可以自定义ref在自定义组件中的放置方式和位置。此外,forwardRef是将ref传递给自定义函数组件的唯一方法
首先,了解ref在类组件、函数组件和常规DOM元素上的工作方式不同是很重要的
从:
ref的值因节点类型而异:
function AutoFocusInput() {
const inputRef = useRef(null);
// This effect runs only once after the component mounts (like componentDidMount)
useEffect(() => {
// refs on regular DOM elements (e.g. the "input" tag) have access to the DOM node
inputRef.current.focus();
}, []);
return <input ref={inputRef} />
}
函数自动聚焦输入(){
const inputRef=useRef(null);
//此效果仅在安装组件后运行一次(如componentDidMount)
useffect(()=>{
//常规DOM元素(例如“input”标记)上的引用可以访问DOM节点
inputRef.current.focus();
}, []);
返回
}
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 = () => {
// refs on class components: hold the class component instance,
// allowing us to call its methods!
this.childRef.current.toggleColor();
}
render() {
return (
<div>
<button onClick={this.handleButtonClicked}>toggle color!</button>
<Child ref={childRef} />
</div>
);
}
}
类子级扩展组件{
状态={color:“red”}
toggleColor=()=>this.setState({color:this.state.color====“红色”?“蓝色”:“红色”})
render(){
回程
}
}
类父级扩展组件{
childRef=createRef();
把手按钮点击=()=>{
//类组件参考:保留类组件实例,
//允许我们调用它的方法!
this.childRef.current.toggleColor();
}
render(){
返回(
切换颜色!
);
}
}
3.现在,最后回答你的问题。无法将引用传递给函数组件,因为它们没有实例!
将ref传递给函数组件的唯一方法是使用forwardRef。使用forwardRef时,您可以简单地将ref传递给DOM元素,这样父元素就可以像示例1中那样访问它,或者您可以使用UseImperialiveHandle钩子创建一个包含字段和方法的对象,这类似于eample 2
3.1只需将ref传递给DOM元素:
// Only when using forwardRef, the function component receives two arguments,
// props and ref (Normally the component only gets the props argument).
const RedInput = forwardRef((props, ref) => {
// passing the ref to a DOM element,
// so that the parent has a reference to the DOM node
return <input style={{color: "red"}} {...props} ref={ref} />
});
function AutoFocusInput() {
const inputRef = useRef(null);
// This effect runs only once after the component mounts (like componentDidMount)
useEffect(() => {
// ref on function component is forwarded to a regular DOM element,
// so now the parent has access to the DOM node including its focus method.
// Note that the ref usage is the same as a regular
// DOM element, like in example 1!
inputRef.current.focus();
}, []);
return <RedInput ref={inputRef} />
}
//仅当使用forwardRef时,函数组件接收两个参数,
//props和ref(通常组件只获取props参数)。
常量RedInput=forwardRef((道具,ref)=>{
//将ref传递给DOM元素,
//这样父节点就有了对DOM节点的引用
返回
});
函数AutoFocusInput(){
const inputRef=useRef(null);
//此效果仅在安装组件后运行一次(如componentDidMount)
useffect(()=>{
//函数组件上的ref被转发到常规DOM元素,
//因此,现在父节点可以访问DOM节点,包括它的focus方法。
//请注意,ref用法与常规用法相同
//DOM元素,如示例1所示!
inputRef.current.focus();
}, []);
返回
}
3.2将父引用附加到自定义对象:
要将函数或字段附加到ref,就像处理类组件的实例一样,需要使用`useImperialiveHandle`钩子:
const Child = forwardRef((props, ref) => {
const [color, setColor] = useState("red");
// To customize the value that the parent will get in their ref.current:
// pass the ref object to useImperativeHandle as the first argument.
// Then, whatever will be returned from the callback in the second argument,
// will be the value of ref.current.
// Here I return an object with the toggleColor method on it, for the parent to use:
useImperativeHandle(ref, () => ({
toggleColor: () => setColor(prevColor => prevColor === "red" ? "blue" : "red")
}));
return <div style={{backgroundColor: color}}>yo</div>;
});
class Parent extends Component {
childRef = createRef();
handleButtonClicked = () => {
// Ref passed to a function component wrapped in forwardRef.
// Note that nothing has changed for this Parent component
// compared with the class component in example 2!
this.childRef.current.toggleColor();
}
render() {
return (
<div>
<button onClick={this.handleButtonClicked}>toggle color!</button>
<Child ref={childRef} />
</div>
);
}
}
const Child=forwardRef((props,ref)=>{
const[color,setColor]=使用状态(“红色”);
//要自定义父级将在其ref.current中获得的值,请执行以下操作:
//将ref对象作为第一个参数传递给UseImperializeHandle。
//然后,在第二个参数中,无论回调返回什么,
//将是参考电流的值。
//在这里,我返回一个带有toggleColor方法的对象,供父对象使用:
使用命令式句柄(参考,()=>({
toggleColor:()=>setColor(prevColor=>prevColor==“红色”?“蓝色”:“红色”)
}));
返回哟;
});
类父级扩展组件{
childRef=createRef();
把手按钮点击=()=>{
//Ref传递给封装在forwardRef中的函数组件。
//请注意,此父组件没有任何更改
//与示例2中的类组件相比!
this.childRef.current.toggleColor();
}
render(){
返回(
切换颜色!
);
}
}
答案取决于您想对ref做什么。有关使用forwardRef
的不同方法,请参阅下面我的详细答案。