Dr.YSG
Dr.YSG

Reputation: 7591

How to bind one React Functional Component to another? (DevExtreme Chart to PivotGrid)

We prefer to use functional statetless react components as much as possible (especially now with React Hooks).

However, I cannot figure out how to achieve the effect of binding a DevExtreme PivotGrid to a Chart (so that one gets a combined operation).

As you can see from their example: https://js.devexpress.com/Demos/WidgetsGallery/Demo/PivotGrid/ChartIntegration/React/MaterialTealDark/

They use Class components with ref's and then do when the combined Class component mounts:

  componentDidMount() {
    this._pivotGrid.bindChart(this._chart, {
      dataFieldsDisplayMode: 'splitPanes',
      alternateDataFields: false
    });
  }

We would rather not go that way. Is there some neat trick one can use with the new React useRef() hook, or by giving HTML doc id's to the chart so that we can bind the two components at some time after the initial load?

We are not purists here, so even slightly ugly solutions would do.

Upvotes: 2

Views: 980

Answers (1)

P Fuster
P Fuster

Reputation: 2344

I can't think of anything but a simple change to doing it the Hooks way, aka put the code in the useEffect() hook and use useRef() to bind the refs:

// import useEffect and useRef hook from 'react', 
import React, { useEffect, useRef() } from 'react'    

function App() {
  // initialize the ref variables with null as the initial value,
  const pivotGrid = useRef(null);
  const chart = useRef(null);

  // useEffect runs after the layout paint...
  useEffect(() => {
      // do the binding on the references,
      pivotGrid.current.bindChart(chart.current, {
         dataFieldsDisplayMode: 'splitPanes',
         alternateDataFields: false
      });
  }
  ,
  // we pass an empty array to only run once after the component mount,
  [])

  // pass the refs variables to the components.
  return (
  <React.Fragment>
    <Chart ref={chart}>
      <Size height={320} />
      <Tooltip enabled={true} customizeTooltip={customizeTooltip} />
      <CommonSeriesSettings type={'bar'} />
      <AdaptiveLayout width={450} />
    </Chart>

    <PivotGrid
      id={'pivotgrid'}
      dataSource={dataSource}
      allowSortingBySummary={true}
      allowFiltering={true}
      showBorders={true}
      showColumnTotals={false}
      showColumnGrandTotals={false}
      showRowTotals={false}
      showRowGrandTotals={false}
      ref={pivotGrid}
    >
      <FieldChooser enabled={true} height={400} />
    </PivotGrid>
  </React.Fragment>
);
}

I'm not 100% sure if you need to pass the ref.current or simply the ref itself . You can try both ways!

EDIT

Re: using useRef(), from the React docs:

Keep in mind that useRef doesn’t notify you when its content changes. Mutating the .current property doesn’t cause a re-render. If you want to run some code when React attaches or detaches a ref to a DOM node, you may want to use a callback ref instead.

Upvotes: 1

Related Questions