1

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

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

不幸的是,这些 BoltOns 似乎没有以我期望的方式响应状态更新,因此我无法正确设置事件处理程序。我的问题在下面的评论中注明。一般来说,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>
    );

}

谁能建议一种替代模式,或者网络库?(我已经做了两个动作。)

4

1 回答 1

0

经过一些试验和错误,下面的结果对我来说效果最好。

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>
    );
}

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

我还相信渲染一次并将状态更新作为突变进行通信应该可以通过跳过网络初始化来提高性能。话虽如此,我还没有编写任何性能测试。

于 2021-12-27T17:29:40.967 回答