如何使用 Cytoscape.js 创建功能性 React 组件?

How to create a Functional React Component using Cytoscape.js?

我正在使用 Cytoscape.js 和 React。我有一个功能性的 GraphComponent,它接收用于呈现 Cytoscape 图的元素列表,以及我希望设置动画的节点列表。

我遇到的问题是我不知道如何保留 'cy' 对象以便以后可以访问它。具体来说,我想向路径中的节点添加一个 class。

const MyComponent = ({ myElements, path }) => {
    
    useEffect(() => {

        const cy = {
            ...
            elements: myElements
            ...
        }

    }, []);

    
    useEffect(() => {

        // This fails since 'cy' is undefined
        cy.$id("A").addClass("highlighted");

    }, [path]);

    return (
        <div id="cy" />
    );
}

想法 #1:创建一个变量 'cy' 然后我可以在 useEffect 中设置值。

问题:初始渲染后 'cy' 的值丢失

const MyComponent = ({ myElements, path }) => {

    let cy;
    
    useEffect(() => {

        cy = {
            ...
            elements: myElements
            ...
        }

    }, []);

    useEffect(() => {

        // This fails since 'cy' is undefined
        cy.$id("A").addClass("highlighted");

    }, [path]);

    return (
        <div id="cy" />
    );
}

想法 #2:将 cy 保存为状态。

问题:Cy 未正确初始化

const MyComponent = ({ myElements, path }) => {

    const [cy, setCy] = useState({});
    
    useEffect(() => {

        setCy({
            ...
            elements: myProp
            ...
        });

    }, []);

    useEffect(() => {

        cy.$id("A").addClass("highlighted");

    }, [path]);

    return (

        // This fails since cy is not initialized to a cytoscape object when component mounts
        <div id="cy" />
    );
}

所以问题是,如何在 React 功能组件中创建和访问 cytoscape 对象(并修改其节点和元素)?

您通常不想在状态中存储道具,因为您已经将其存储在其他地方。如果您通过道具为 cy 传递数据,只需使用道具。

一般来说,如果您尝试根据外部更改保持状态更新,则需要向 useEffect 挂钩添加依赖项。一个空数组意味着效果只会 运行 一次,在挂载时。

参考文档以获得很好的教程,但通常它是这样工作的:

useEffect(()=> {
   setSomeState(/* set state */)
}, [someValue])

如果 someValue 保持不变,则效果不会 re-run。如果它发生变化,效果将 运行 下次渲染时(由于道具或状态变化)。

同样,如果数据是通过 prop 传入的,请不要将其设置为状态。如果您想跟踪基于该 prop 的组件内部的某些内容,那么 useEffect 和对 prop 的依赖将为您解决这个问题。

编辑评论

声明在渲染之间保存数据的位置。如果问题是你不应该渲染,因为挂载上没有值(但会在另一个渲染中),那么将它包装在一个表达式中,例如,

{someValueOrExpression ? <div id="cy" /> : <div>Empty State</div>}

{someValueOrExpression && <div id="cy" />}

这样 div 就不会显示和失败,直到它具有正确呈现所需的内容。