React使用ref调用子组件方法时ref.current返回undefined如何解决
核心原因
子组件未完成挂载流程时,实例、内部方法以及通过useImperativeHandle暴露的方法都未初始化,所以不可能直接调用不存在的方法,你可以通过以下两种方案实现需求:
方案1:加载状态提升到父组件管理(推荐)
将加载状态的控制权放到父组件,通过props传递给子组件,子组件自己监听状态变化触发对应逻辑,完全不需要依赖ref调用。
父组件代码
import { useState, useRef } from 'react'; const ParentComponent = ({ actions,...props}) => { const [isLoading, setIsLoading] = useState(false); const activeListPageRef = useRef(); const getResources = async(resourceIds) => { setIsLoading(true); try { // 此处写你的接口请求逻辑 await fetchResources(resourceIds); } finally { setIsLoading(false); } } return ( <ChildComponent ref={activeListPageRef} isLoading={isLoading} /> ) }
子组件代码
import { useState, useEffect, useImperativeHandle, forwardRef } from 'react'; // 必须用forwardRef包裹才能接收父组件传的ref const ChildComponent = forwardRef(({ tableData, isLoading, ...props}, ref) => { const [gridApi, setGridApi] = useState(); const onBtShowLoading = () => { gridApi?.showLoadingOverlay(); }; const onBtHide = () => { gridApi?.hideOverlay(); }; const onGridReady = (params) => { setGridApi(params.api); }; // 监听父组件传的加载状态自动调用对应方法 useEffect(() => { if (!gridApi) return; isLoading ? onBtShowLoading() : onBtHide(); }, [isLoading, gridApi]); useImperativeHandle(ref, () => ({ onGridReady, onBtShowLoading, onBtHide })); // 此处省略子组件原有渲染逻辑 return <div>你的表格组件</div> }); export default ChildComponent;
方案2:缓存调用队列(适合无法提升状态的场景)
如果确实需要通过ref调用,可以将子组件挂载前的调用请求缓存到队列,等子组件挂载完成后再批量执行。
父组件代码
import { useRef, useEffect } from 'react'; const ParentComponent = ({ actions,...props}) => { const activeListPageRef = useRef(); // 存储未挂载时的调用请求 const pendingCallQueue = useRef([]); // 统一封装子组件方法调用逻辑 const callChildMethod = (methodName, ...args) => { if (activeListPageRef.current) { activeListPageRef.current[methodName](...args); } else { pendingCallQueue.current.push({ methodName, args }); } }; // 子组件挂载后执行缓存的调用 useEffect(() => { if (activeListPageRef.current) { pendingCallQueue.current.forEach(({ methodName, args }) => { activeListPageRef.current[methodName](...args); }); pendingCallQueue.current = []; } }, [activeListPageRef.current]); const getResources = async(resourceIds) => { callChildMethod('onBtShowLoading'); try { // 此处写你的接口请求逻辑 await fetchResources(resourceIds); } finally { callChildMethod('onBtHide'); } } return ( <ChildComponent ref={activeListPageRef} /> ) }
原有代码问题说明
- 子组件没有用
forwardRef包裹,父组件的ref无法正常传递到子组件,这是你ref.current一直为undefined的核心原因之一 - 请求完成后调用
onBtHide时没有加非空判断,若请求速度快于子组件挂载速度会直接报错
内容的提问来源于stack exchange,提问作者user2128
相关产品推荐
相关产品推荐

