简体   繁体   中英

In React I get the warning: Function component cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

Here's are a few snippets from my code. I have a function component defined as:

function AssociationViewer(props) {
    const core = React.useRef<GraphCore | null>(null);
    const dataService = React.useRef<DataService>(new DataService(props.graphApi));
    const selectionBoxDimensions = React.useRef(null);
    const initialGraphRender = React.useRef<boolean>(false);
    const filterRef = React.useRef(null);

    const getElementRef = React.useCallback((el) => {
        if (el && !core.current) {
            core.current = new GraphCore({ container: el });
            // TODO: Change data service to accept core as an argument and initialize it here?
            dataService.current.addGraphDataFn = (opts) => getRksGraph().addData(opts);
            dataService.current.setGraphDataFn = (opts) => getRksGraph().setData(opts);
            onMount();
            return onUnmount;
        }
    }, []);
.
.
.
    return (
        <>
            {props.enableSearch && <div style={{zIndex: 10000, position: 'absolute', marginTop: 10, right: 15}}>
                <button onClick={flashSearchedNodes}>Search</button>
                <input
                    value={searchText}
                    placeholder='Find node by text'
                    onKeyDown={(e) => e.key == 'Enter' && flashSearchedNodes()}
                    onChange={(e) => setSearchText(e.target.value)}
                />
                <input readOnly style={{width: '60px', textAlign: 'center'}} type="text" value={searchedElesDisplayText} />
                <button onClick={prevFoundNode}>Prev</button>
                <button onClick={nextFoundNode}>Next</button>
                <button onClick={cancelFlashNodes}>Clear</button>
            </div>}
            <div
                style={{ height: '100%', width: '100%' }}
                id={props.componentId || 'kms-graph-core-component'}
                ref={getElementRef}
            ></div>
            {core.current && (
                <GraphTooltip
                    tooltip={props.tooltipCallback}
                    tooltipHoverHideDelay={props.tooltipHoverHideDelay}
                    tooltipHoverShowDelay={props.tooltipHoverShowDelay}
                    tippyOptions={props.tippyOptions}
                    core={core.current}
                />
            )}
            {props.loadingMask && !hasCustomLoadMask() && (
                <DefaultLoadMask
                    active={showLoading}
                    loadingClass={getLoadingClass()}
                    onClick={() => {
                        setShowLoading(false);
                    }}
                />
            )}
            {props.loadingMask && showLoading && hasCustomLoadMask() && props.customLoadingMask()}
        </>
    );
}

export default AssociationViewer;

I have an angular app that uses a service to call this component as follows:

ReactService.render(AssociationViewer,
{
     ref: function (el) {
          reactElement = el;
     },
     component: 'association-viewer-1',
     getImageUrl: getImageUrl,
     graphApi: graphApi,
     pairElements: $ctrl.pairElements,
     theme: theme,
     view: 'testView'
}
'miniGraphContainer',
() => {
          if ($ctrl.pairElements.edges) {
               reactElement.core.select($ctls.pairElements.edges($ctrl.currEdge).id);
          }
}

Here's GraphTooltip:

import React from 'react';
import GraphCore from '../GraphCore';

function useForceUpdate() {
    const [value, setValue] = React.useState(0);
    return () => setValue((value) => ++value);
}

interface IGraphTooltipProps{
    tooltipHoverShowDelay: number;
    tooltipHoverHideDelay: number;
    core: GraphCore;
    tooltip: Function;
    tippyOptions: any;
}

const GraphTooltip = (props: IGraphTooltipProps) => {
    const tooltipRef = React.useRef<React.Element>(null);
    const forceUpdate = useForceUpdate();

    const setRef = (ref) => {
        tooltipRef.current = ref;
    };

    const [currentElement, setCurrentElement] = React.useState<React.Element>();

    React.useEffect(() => {
        props.core.getAllSubGraphs().forEach((subgraph) => {
            subgraph.setOptions({
                tooltip: {
                    domElementCallback: (e) => {
                        // this isn't changing so it's not picking up a render loop
                        setCurrentElement(e);
                        forceUpdate();
                        return tooltipRef.current;
                    },
                    hoverShowDelay: props.tooltipHoverShowDelay,
                    hoverHideDelay: props.tooltipHoverHideDelay,
                    options: props.tippyOptions
                }
            });
        });
    }, []);

    return <>{props.tooltip(setRef, currentElement, props.core)}</>;
};

export default GraphTooltip;

When triggering the event that causes this ReactService to render the AssociationViewer component, I get the warning: Function component cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()? Also, reactElement is undefined since the ref cannot be accessed. How can I use React.forwardRef() in the AssociationViewer component to forward the ref to the calling component?

So, here you just have to wrap your functional component inside React.forwardRef()

<GraphTooltip
    tooltip={props.tooltipCallback}
    tooltipHoverHideDelay={props.tooltipHoverHideDelay}
    tooltipHoverShowDelay={props.tooltipHoverShowDelay}
    tippyOptions={props.tippyOptions}
    core={core.current} // Due to this you are getting warning
/>

Go to your functional component "GraphTooltip" and wrap your export statement in forwardRef().

export const React.forwardRef(GraphTooltip)

Hope it helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM