We have updated Flexmonster Software License Agreement, effective as of September 30, 2024. Learn more about what’s changed.

ref.current.flexmonster() returns null

Resolved
dan asked on April 21, 2020

Hi 
I am trying to integrate the react widget but cannot figure out how to refresh the pivottable. When using webdatarocks I managed to use ref.current.webdatarocks.setReport to refresh it, however when switching to flexmonster the similar call ref.current.flexmonster() return null (ref.current is not null). 
 
I am using react functional components and the following is a snippet 
function PivotTable(props) {
....

const ref = React.useRef(null);
.....

 
return (<FlexmonsterReact.Pivot 
                        ref={ref} 
                        toolbar={true} 
                        width="100%" 
                        licenseKey="......"
                        reportcomplete={onReportComplete}
                    />);
}

12 answers

Public
Vera Didenko Vera Didenko Flexmonster April 21, 2020

Hello, Dan,
 
Thank you for reaching out to us. 
 
We have not managed to reproduce the issue: when React.useRef(null); is used to create the reference to the Flexmonster instance, Flexmonster API calls are accessible, for example, calling setReport():

function onReportComplete(){
ref.current.flexmonster().off("reportcomplete");
ref.current.flexmonster().setReport(report);
}

We kindly suggest seeing our sample React project on GitHub.
In case it doesn't help, could you please modify the sample so that the issue is reproducible?
This will help us to make further progress in solving the problem.
 
Looking forward to your reply.
 
Kind regards,
Vera

Public
dan April 21, 2020

Hi Vera
I see the same null issue in onReportComplete, following is the error screen of React dev
TypeError: Cannot read property 'getReport' of null

onReportComplete
C:/vsProjects/laser-ui/src/pages/PivotFM.js:298

  295 | 
296 | const onReportComplete = () => {
297 | const flexMonsterRef = ref.current.flexmonster();
> 298 | console.log(">>>>", flexMonsterRef.getReport());
| ^ 299 | }
300 |
301 | return (

View compiled

(anonymous function)
C:/vsProjects/laser-ui/node_modules/flexmonster/flexmonster.full.js:9

Public
Vera Didenko Vera Didenko Flexmonster April 23, 2020

Hello, Dan,
 
Thank you for your response.
 
Still, we have not managed to reproduce the issue using our sample project on GitHub.
The following code snippet compiles and runs successfully: 

import React from 'react';
import * as FlexmonsterReact from 'react-flexmonster/hooks';

function PivotTableHooks (props) {

const ref = React.useRef(null);

const onReportComplete = () => {
const flexMonsterRef = ref.current.flexmonster();
console.log(">>>>", flexMonsterRef.getReport());
}

return <div className="App">
<FlexmonsterReact.Pivot
ref={ref}
toolbar={true}
width="100%"
report="https://cdn.flexmonster.com/reports/report.json"
reportcomplete={onReportComplete}/>
</div>;
}

export default PivotTableHooks;

Please let us know if there is something we are missing. 
Also, could you please confirm if you have managed to run our sample Flexmonster with the React project successfully?
 
Waiting for your reply.
 
Kind regards,
Vera

Public
dan April 23, 2020

Thanks Vera, I am still facing the same issue.
In my project I still have packages dependencies on webdatarocks (as i am showing both widgets as a demo), would that be interferring with flexmonster and causing this?
 
 

Public
Vera Didenko Vera Didenko Flexmonster April 23, 2020

Hello, Dan,
 
Thank you for your response. 
 
We would like to confirm that there should be no conflicts between Flexmonster and WebDataRocks. 
Adding both Flexmonster and WebDataRocks to the same functional component works fine on our end. 
We have assigned a separate ref object for each of them, for example: 

import React from 'react';
import * as FlexmonsterReact from 'react-flexmonster/hooks';
import * as WebDataRocksReact from './webdatarocks.react';


function PivotTableHooks (props) {


const refFlex = React.useRef(null);

const refWeb = React.useRef(null);


const onReportCompleteFlex = () => {

const flexMonsterRef = refFlex.current.flexmonster();
console.log("Flexmonster >>>>", flexMonsterRef.getReport());
}


const onReportCompleteWeb = () => {

const weDataRocksRef = refWeb.current.webdatarocks;
console.log("WebDataRocks >>>>", weDataRocksRef.getReport());

}


return <div className="App">

<FlexmonsterReact.Pivot
ref={refFlex}
toolbar={true}
width="100%"
report="https://cdn.flexmonster.com/reports/report.json"
reportcomplete={onReportCompleteFlex}/>

<WebDataRocksReact.Pivot
ref={refWeb}
toolbar={true}
width="100%"
report="https://cdn.webdatarocks.com/reports/report.json"
reportcomplete={onReportCompleteWeb}/>

</div>;

}

export default PivotTableHooks;

Please let us know if there is something else that we might have missed. 
 
Also, we have attached the simple React project with Flexmonster and WebDataRocks that we have created in the process (please see Flexmonster_WebDataRocks_React_project.zip in the attachments below).
To start the project, please run the following commands: 

  1. npm install
  2. npm start

 
Could you please confirm if the project works on your end also?
 
Looking forward to your reply. 
 
Kind regards, 
Vera

Public
dan April 25, 2020

After a lot of trail and error I found that one of the parent component's useEffect has setState calls, removing that solved the null issue in onReportComplete.
However when i try to get the ref (ie, ref.current.flexmonster()) from within the same component's reducer function I met the same issue again. Right now my work around is to save the flexmonster ref returned in onReportComplete to some global variables and then use that in the reducer, but this seems rather 'ugly'.
let flexMonster=null;
function Piv (props) {
....
   function reducer(action) {
       ....
     switch(action.type) {
      case 'dataLoaded':
       flexMonster.setReport({....});
     ......
   }

   const onReportComplete = () => {
        if (flexMonster ===null) {
            flexMonster = fmRef.current.flexmonster();
        }
        console.log(">>>>", flexMonster.getReport());
    }

....
    return (<......>);
}
 
 
Is there a better way to do it? I need to refresh the report data after user changed values in the input form and I am doing it via reducer currently.

Public
Vera Didenko Vera Didenko Flexmonster April 29, 2020

Hello, Dan, 
 
Thank you for giving us some time.
 

  1. To avoid possible misunderstandings, we would like to provide a summary of the case so far: 

    1.1) You integrated WebDataRocks with React successfully: calling WebDataRocks API calls works.
    1.2) You integrated Flexmonster with React, however, calling Flexmonster API calls results in null.
    1.3) Our team has not managed to reproduce the issue on our end using our sample project.
    1.4) You have found a way to fix the issue, however, you are searching for a better solution.

  2. Brining the above points together, we kindly recommend the following course of action:

    2.1) Integrating Flexmonster using the React Class Component approach:

    Judging from the code snippets, it seems you are using Flexmonster for React Hooks.
    Please notice that in contrast WebDataRocks integration is based on a React Class Component.

    Hence, our team kindly suggests trying integrating Flexmonster into your React project using a React Class Component.

    Please let us know if this helps to solve the issue.

    2.2) If using the React Class Component approach doesn't help, or is not appropriate for your case:

    Please kindly note that it is essential for our team to reproduce the same issue you encounter in order to fix the problem.

    Therefore, our team kindly asks if you could provide the React sample project (with dummy data) where the issue occurs (this can be done via email).

    This will help us to make further progress in solving the problem and provide an appropriate solution.

 
 
Waiting for your reply.
 
Kind regards,
Vera

Public
Kevin May 14, 2020

Hi,
I'm having the same issue with unavailable flexmonster instance.
I also had that issue with wdr.
The problem is that if you re-render too quickly (under 1.5s approx), reportcomplete callback will be called but the flexmonster instance will be gone already. On my case, reportcomplete is only called once, unfortunately.

  1. Render
  2. Flexmonster initialization
  3. Re-render
  4. Flexmonster is resetting
  5. reportcomplete is called, monster is gone

I understand that Flexmonster is not binded to data and I have to manually call updateData, Am I right ?
Also, you can try "react-debounce-render" and export your PivotTable like this :

export default debounceRender(FlexMonster, 1500);

You'll notice that from now, you'll always have an instance.
The problem is, since I cannot bind data, I have to use effect and that will always force a render, killing flexmonster.
Do you have a solution for this ?
Thanks

Public
dan May 14, 2020

I have switched to use the class component approach and it seems to work fine, although I'd prefer using function components as that's the way forward for React I think.
By binding data I think you mean Flexmonster does not use React's states? Right now I am using setReport() to feed data into Flexmonster... my guess is FM only barely integrates with React 🙂

Public
Kevin May 14, 2020

I'll try the class component.
I agree with you, the react library is just a wrapper around a library (using global state).

Public
Kevin May 15, 2020

I somehow fixed my problem...

  1. I create a wrapper
  2. I added a random key to the flexmonster <Pivot /> using uuid :
    <Pivot
    key={`flexmonster:${v4()}`}
    ref={flexMonsterRef}
    {... pivotProps}
    />
  3. I used React.memo to memoized the whole component and only listen for data update using lodash :
    export default memo(FlexMonster, (prevProps, nextProps) => (
    _isEqual(prevProps.data, nextProps.data)
    && _isEqual(prevProps.showToolbar, nextProps.showToolbar)
    ))

Explanation :
Since we're using a random key, React will never reuse the same Flexmonster instance for the same render, forcing it to refresh properly and allowing me to bind data like any other react components. I'm making sure I only render the component if the data change. (PivotConfig won't be binded to avoid too much renders)
 
That way, I always have access to the instance. Flexmonster will dispose the unmounted instance asyncronously.
Note: I'm also using debounceRender with a 250ms to avoid quick (and expensive) renders.

Public
Mykhailo Halaida Mykhailo Halaida Flexmonster May 18, 2020

Hi Kevin,
 
It is great to hear that you've managed to fix the mentioned issue.
 
Also, thank you for sharing your insights, we hope this helps someone in the future. In case you have any updates regarding this approach, feel free to share them here.
 
Have a great week!
 
Regards,
Mykhailo

Please login or Register to Submit Answer