useRef current仅在第二次更新时获得其值

时间:2020-06-05 11:33:49

标签: javascript reactjs typescript visnetwork

我具有以下组成部分:

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;

当我致电network.current.filter([...])时,它将设置filterNodes状态。另外,它应该将filterNodesRef设置在useEffect内。

但是,filterNodesRef.current仍然是空数组。

但是当我第二次调用network.current.filter([...])时,只有filterNodesRef.current得到了值,而DataView才能够进行过滤。

为什么会这样?我认为useRef.current将始终包含最新值。

3 个答案:

答案 0 :(得分:3)

我终于通过在refresh()内而不是useEffect方法内调用filter()方法来解决了这个问题:

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

答案 1 :(得分:2)

设置引用的.current不会通知组件有关更改。一定有其他原因才能使其第二次运行。

来自https://reactjs.org/docs/hooks-reference.html#useref

请记住,useRef的内容更改时不会通知您。更改.current属性不会导致重新渲染。如果您想在React将ref附加或分离到DOM节点时运行一些代码,则可能要改用回调ref。

您可能要使用useState,因为这确实会重新呈现组件。

还有两件事

  1. 我不确定networkRef.current.filter(["id0, id1, id2"])是什么。当我尝试做['a'].filter(['a'])时,Typescript确实抱怨了,但我从未见过,所以您确定这是您想做的吗?

  2. 如果要传递参考,可能有更好的方法。也许考虑重新考虑组件之间的关系。这样做是因为您需要访问多个组件中的networkRef?如果是,则可能要查看providers

如果这不能回答您的问题,请写评论(请写一些具体说明),我们很乐意为您提供帮助:)

答案 2 :(得分:0)

是的,useRef.current包含最新值,但是您在filterNodesRef.current中的useEffect就是为什么在初始渲染中获得空数组的原因。

  • VisNetwork的初始呈现filterNodes是一个空数组==> filterNodesRef.current保持为空。由于setFilterNodes(items);是异步函数=>事件,因此您在useImperativeHandle中进行了设置,它将在第二次渲染中更新。

  • useImperativeHandle中,您设置了setFilterNodes(items); ==> filterNodes已更新,并且VisNetwork重新渲染==> useEffect被触发==> {{ 1}}设置为新的filterNodesRef.current

让我们尝试一下:

filterNodes