我怎样才能在 Vis.js 网络的这个可变引用更新时引起其他组件的重新渲染?有更好的套餐吗?

How can I induce rerendering of other components on an update to this mutable ref to Vis.js network? Is there a better package available?

我正尝试在 React 中使用 Vis.js 并开始使用 James Tharpe 分享的模式:https://www.jamestharpe.com/react-visjs/

我还试图包括我称之为 BoltOns 的东西,它以网络状态作为参数,允许它们根据需要操纵事件处理程序。

不幸的是,这些 BoltOn 似乎没有以我期望的方式响应状态更新,因此我无法正确设置事件处理程序。我的问题在下面的评论中指出。一般来说,BoltOns 作用的对象似乎是一个落后的更新。看起来它应该能够以这种方式工作,就好像我触发我的开发服务器重新编译行为是预期的那样。

export const NetworkDiagram : FC<NetworkDiagramProps>  = ({
    nodes,
    edges,
    BoltOns = [DefaultNetworkDiagramToolbar, NetworkDiagramEditor],
    options
}) =>{

    // Forces an update.
    // Despite using memo below,
    // this causes a circular update.
    const [tick, forceUpdate] = useReducer(x=>x+1, 0);

    // A reference to the div rendered by this component
    const domNode = useRef<HTMLDivElement>(null);

    // A reference to the vis network instance
    const network = useRef<Network | null>(null);

    // An array of nodes
    const _nodes = convertNodesToDataSet(nodes||{});

    const data: Data = {
        nodes  : _nodes,
        edges : edges
    };


    useEffect(() => {
        if (domNode.current) {
            network.current = new Network(domNode.current, data, {});
            network.current.setOptions({
                physics : true,
                height : "100%",
                width : "100%",
                ...options
            });
            forceUpdate();
            // This also fails if I limit the number of ticks to 5.
            // The ref ref received still does not properly allow me to set the event
            // handlers.
            // I have also tried 
            // if(!initLoad) setInitLoad(true);
            // but this produces the same behavior as limiting the number of ticks.
        }
    }, [domNode, network, data, options]);

    return (
        <div style={{
            position : "relative",
            height : "100vh",
            width : "100vw"
        }}>
            {BoltOns.map((BoltOn)=><BoltOn updateCount={tick} network={network} domNode={domNode}/>)}
            {useMemo(()=><div style={{
                height : "100vh",
                width : "100vw"
            }} ref={domNode}/>, [domNode, network, data, options])}
        </div>
    );

}

任何人都可以建议替代模式,或者网络库吗? (我已经做了两步了。)

经过反复试验,下面的方法最适合我。

export interface NetworkDiagramProps{
    nodes ? : {[key : string] : NodeDetailsI}
    edges ? : Edge[],
    BoltOns ? : NetworkDiagramBoltOn[]
    options ? : Options,
    extractNetwork ? : (network ? : Network)=>any
}

/**
 * A React
 * @param param0 
 * @returns 
 */
export const NetworkDiagram : FC<NetworkDiagramProps>  = ({
    nodes,
    edges,
    BoltOns = [DefaultNetworkDiagramToolbar, NetworkDiagramEditor],
    options,
    extractNetwork
}) =>{

     const network = useRef<Network|undefined>(undefined);

    // A reference to the div rendered by this component
    const domNode = useRef<HTMLDivElement>(null);

    // I'm only accepting nodes as an object, with keys for ids.
    const _nodes = convertNodesToDataSet(nodes||{});

    const data = {
        nodes  : _nodes,
        edges : new DataSet(edges||[])
    };

    useEffect(()=>{
        if(domNode.current && !network.current) network.current = new Network(domNode.current, data, {});
    }, [domNode.current])


    // We need the component to be rerendered once
    // after the domNode has been rendered and the network initialized.
    const [tick, forceUpdate] = useReducer(x=>x+1, 0);
    useEffect(()=>{
        forceUpdate();
    }, [])
    
    // handle new data on options by mutably setting the data and options
    useEffect(()=>{
        network.current?.setData(data);
    }, [data, tick])
    useEffect(()=>{
        network.current?.setOptions(options||{});
    }, [options, tick])

    // allow network to be extracted
    useEffect(()=>{
        extractNetwork && extractNetwork(network.current);
    }, [tick])

    // And, the teardown
    useEffect(()=>{
        return ()=>{
            if(network.current){
                network.current.destroy();
                delete network.current;
            }
        }
    }, [])

    return (
        <div style={{
            position : "relative",
            ...style
        }}>
            {useMemo(()=><div style={{
                height : "100%",
                width : "100%"
            }} ref={domNode}/>, [domNode])}
            {BoltOns.map((BoltOn)=><BoltOn
            edges={data.edges}
            nodes={data.nodes}
            network={network.current}/>)}
        </div>
    );
}

到目前为止,我在使用这种方法时没有遇到任何意外行为。

我还认为渲染一次并将状态更新作为突变进行通信应该通过跳过网络初始化来提高性能。也就是说,我还没有编写任何性能测试。