How to update the state/props of a custom visualisation component after the initial render?

I have been trying to create a custom visulaisation for Kibana 6.5.4. I have written a custom component, request and response handler. I get the data for my visualisation from the props.visData attribute. However this data only gets updated once, when the component initially renders. If I change the time period via kibana's time picker and make the request again, I can see that my response handler has the new data, but that this is not passed down into my visualisation component.

In my visualisation component's constructor I am adding a variable called skyplotData to the component state, and setting its value to the props.visData attribute. I then use skyplotData to populate the plot of my visualisation.

How can I ensure that the state is updated when the user changes the time period via the time picker on Kibana?

Code below is that of my visualisation component:

import React from 'react';
import Plot from 'react-plotly.js';

import {
  EuiPage,
  EuiPageHeader,
  EuiTitle,
  EuiPageBody,
  EuiPageContent,
  EuiPageContentHeader,
  EuiPageContentBody,
  EuiText
} from '@elastic/eui';


const plotLayout = {
  showlegend: true,
  width: 800, height: 800,
  polar: {
    radialaxis: {
      range: [90, 0], //Sets x axis range. Default is 0 to largest value in the dataset
      tickmode: 'array',
      tickvals: [90, 75, 60, 45, 30, 15, 0], //Sets how many ticks to show on the plot
      tickfont: {
        size: 8
      }
    },
    angularaxis: {
      tickfont: {
        size: 8
      },
      direction: 'clockwise'
    }
  }
};

const plotConfig = { displayModeBar: false }; //Hides options to zoom, screenshot etc.

export class SelfChangingComponent extends React.Component {
  constructor(props) {
    super(props);
    //Set the skyplot data in the component state
    this.state = {
      skyplotData: props.visData,
      plotLayout,
      plotConfig
    };
    console.log('visData: ', this.props.visData);
  }

  render() {
    return (
      <EuiPage>
        <EuiPageBody>
          <EuiPageContent>
            <EuiPageContentHeader>
              <EuiTitle>
                <h2>Skyplot</h2>
              </EuiTitle>
            </EuiPageContentHeader>
            <EuiPageContentBody>
              <Plot
                data={this.state.skyplotData}
                layout={this.state.plotLayout}
                config={this.state.plotConfig}
              />
            </EuiPageContentBody>
          </EuiPageContent>
        </EuiPageBody>
      </EuiPage>
    );
  }

  componentDidMount() {
    this.props.renderComplete();
  }

  componentDidUpdate() {
    this.props.renderComplete();
  }
}

From what I understand about React, state changes are usually pushed down from the parent component, but I don't understand how that works in this case, as I don't have a parent component. I have just registered a new visualisation by using VisFactory.createReactVisualization, and added my component to it using:

visConfig: {
      component: SelfChangingComponent,

Can anyone help with this? I can't find any solution to the issue. It's the final issue I'm having with my custom visualisation

@ppisljar @timroes Can one of you provide any insight here? It's been many years since I've had to deal with Kibana visualizations...

Hi,

the problem is, that you're expecting the constructor to be called again in a React component when it's props changes. That is not how React work :slight_smile: You need to use the appropriate lifecycle methods (https://reactjs.org/docs/react-component.html) to transfer changed props into your state if you need that. Please be aware that Kibana 6.5.4 ran on React 16.3, so you don't have getDerivedStateFromProps yet, so instead you'll need to use the componentWillUpdate method instead.

Cheers,
Tim

@timroes Hi,

Apologise for delayed response.

I tried using componentWillUpdate, but I am unable to call setState() from this method, so I am unsure how I can set the new state using this.

I have been able to circumvent my issue by just assigning the data for my plot to the props data directly using data={this.props.visData}. This fulfils my needs for the time being, but I thought the correct approach would be to set it in the state, but I may be incorrect.

On a side note, Tim, is there any chance there will be an updated blog post on creating custom plugin/visualisations in the near future? It has taken me nearly 2 months to get to this stage of my custom visualisation, and most of the time has been spent trying to find updated examples as the current ones are quite out of date, and the newer examples I have been able to find have been hidden in the code base in the most bizarre places. My current plugin is a sort of Frankenstein's monster of code from different sites, blogs and github.

It would be nice if there could even be a small post on the current approach to creating custom kibana plugins :slight_smile:

We are currently in a large phase of refactoring our core fundamental plugin infrastructure. Once that new system exists documentation will be a key new "fix" in that system and there should be way better coverage on how to write plugins than we have today. We already started moving some test plugins into the repository, which are tested on every build. One plan is to document them very explicitly so we have sample plugins that are actually fully tested against Kibana and documented as a reference. You can find those in https://github.com/elastic/kibana/tree/master/test/plugin_functional and we hope to provide more of those tested plugins. Also once different systems move over to the new plugin infrastructure they will have better documentation, since there'll now be a proper API between plugins and you cannot randomly use everything that exists anymore.

Also despite the lag of having proper tutorials on how to write them, we're at least trying to document all changes to existing APIs as good as we can and publish an API changes blog post prior to every release, which will highlight the (what we would consider API) changes in that version (e.g. see the 7.0 changes post). You can find them all in the blog they are usually named "Kibana Plugin API changes" (https://www.elastic.co/search?fv-website_area=blog&fv-product_name=Kibana&q=kibana%20plugin%20api%20changes&size=20)

Cheers,
Tim

@timroes It's great to hear this is being addressed, thanks for the update and for the link to the blog posts for the API changes, I wasn't aware that existed!

On an semi related note, I have opened a new post regarding how to add custom ui drop down boxes and how to pass their values into my search query as filters in a custom visualisation. I haven't been able to find any examples of how to do this within the plugin development documentation. I'd be incredibly greatly if you could take a look at the post to see if you are able to offer any advice/links/code examples to help me achieve this. From what I have read you know the plugin development platform inside out.

Thanks very much for you help :slight_smile:

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.