partridgejiang / Kekule.js

A Javascript cheminformatics toolkit.
http://partridgejiang.github.io/Kekule.js
MIT License
248 stars 61 forks source link

TypeError: Cannot read properties of undefined (reading 'ClassEx') #320

Open mwbouwkamp-mendix opened 3 weeks ago

mwbouwkamp-mendix commented 3 weeks ago

I am trying to wrap kekule into a React widget. I am getting the following error in my console:

TypeError: Cannot read properties of undefined (reading 'ClassEx')
    at kekule.react.base.js:10:22
    at ...

Anyone knows what the problem may be?

Here is my initial (very basic) component:

import { ReactElement, createElement, useState, useRef } from "react";
import { Components } from "kekule-react";

const KekuleComponent = (): ReactElement => {
    const [state, setState] = useState({
        composerPredefinedSetting: 'molOnly',
        chemObj: null
    });

    const composer = useRef<{ getWidget: any }>();

    const onComposerUserModificationDone = () => 
    {
        setState(prevState => {
            return { ...prevState, chemObj: composer.current?.getWidget().getChemObj() }
        });
    }

    return (
        <div>
            <Components predefinedSetting={state.composerPredefinedSetting} onUserModificationDone={onComposerUserModificationDone} />
        </div>
    );
}

export default KekuleComponent;
partridgejiang commented 3 weeks ago

Hi @mwbouwkamp-mendix, the Components is just a namespace wrapping all components in kekule-react package, not a concrete React component. The codes should be modified to somethign like the following ones:

// ...
import { Components } from "kekule-react";
// ...
const Composer = Components.Composer;
const Viewer = Components.Viewer;

const MyComponent = () = {
  // ...
  return (
    <div>
      <Composer predefinedSetting={state.composerPredefinedSetting} onUserModificationDone={onComposerUserModificationDone} />
      <Viewer />
    </div>
  );
};
mwbouwkamp-mendix commented 3 weeks ago

Thank you @partridgejiang. I adapted the code accordingly, but still I get the same error. To reproduce, I just created a new React project with Typescript and added the following component:

import { ReactElement, createElement, useState, useRef } from "react";
import { Components } from "kekule-react";

const KekuleComponent = (): ReactElement => {
    const Composer = Components.Composer;
    const Viewer = Components.Viewer;

    const [state, setState] = useState({
        composerPredefinedSetting: 'molOnly',
        chemObj: null
    });

    const composer = useRef<{ getWidget: any }>();

    const onComposerUserModificationDone = () => 
    {
        setState(prevState => {
            return { ...prevState, chemObj: composer.current?.getWidget().getChemObj() }
        });
    }

    return (
        <div>
            <Composer predefinedSetting={state.composerPredefinedSetting} onUserModificationDone={onComposerUserModificationDone} />
            <Viewer />
        </div>
    );
}

export default KekuleComponent;
partridgejiang commented 3 weeks ago

I have found the problem. Please add the following import at the top of your code:

import { Kekule } from 'Kekule';

Although Kekule is not used directly, some global resources still need to be introduced.

mwbouwkamp-mendix commented 3 weeks ago

Hey @partridgejiang! Two things: 1) it does not solve the problem and 2) the IDE complains that it is declared but never read.

partridgejiang commented 3 weeks ago

Hi @mwbouwkamp-mendix, I have built a demo with vite, please check the attachment, :). react-vite-test.zip

mwbouwkamp-mendix commented 2 weeks ago

Hi @partridgejiang. Thank you for sharing the Vite demo. The good news is that I do get that to work. Also when I create a simple React app using JavaScript, it is working. As soon as I switch to TypeScript, though, I get this error

partridgejiang commented 2 weeks ago

It seems that the import { Kekule } from 'kekule' is eliminated by the TS compiler since variable Kekule is not used in code, so there always be a "ClassEx not found" error. You may add some dummy codes after this import to solve the problem, e.g.:

import { Kekule } from 'kekule';
// ...
console.log(Kekule.VERSION);

or more elegantly, just:

import 'kekule';