Search code examples
javascriptreactjstypescriptvisnetwork

useRef current getting its value only on second update


I have the following components:

const ParentComponent: React.FC = () => {
    const networkRef: any = useRef();

    // Somewhere in the code, I call this
    networkRef.current.filter(["id0, id1, id2"]);

    return (
    ...
        <VisNetwork 
            ref={networkRef}
        />
    ...
    )
}
export default ParentComponent;

interface Props {
    ref: any;
}
const VisNetwork: React.FC<Props> = forwardRef((props: Props, ref) => {
    useImperativeHandle(ref, () => ({
        filter(items: any) {
            setFilterNodes(items);
            nView.refresh();
        }
    }));

    const [filterNodes, setFilterNodes] = useState<any[]>([]);
    const filterNodesRef = useRef(filterNodes);
    useEffect(() => {
        filterNodesRef.current = filterNodes;
    }, [filterNodes]);

    ...
    // Some code to create the network (concentrate on the nodesView filter method)
    const [nView, setNView] = useState<DataView>();
    const nodesView = new DataView(nodes, {
        filter: (n: any) => {
            if (filterNodesRef.current.includes(n.id)) {
                return true;
            }
            return false;
        }
    })
    setNView(nodesView);
    const network = new vis.Network(container, {nodes: nodesView, edges: edgesView}, options);
});
export default VisNetwork;

WHen I call network.current.filter([...]), it will set the filterNodes state. Also, it should set the filterNodesRef inside the useEffect.

However, the filterNodesRef.current remains to be empty array.

But when I call network.current.filter([...]) the second time, only then the filterNodesRef.current got the value and the DataView was able to filter.

Why is it like this? I thought the useRef.current will always contain the latest value.


Solution

  • I finally solved this by calling the refresh() method inside the useEffect instead of the filter() method:

    useEffect(() => {
        filterNodesRef.current = filterNodes;
        nView.refresh();
    }, [filterNodes]);