title: Removing d3-flame-graph when loading new data
body: <p>Recently I picked up a project that has <code>d3-flame-graph</code> on it and the graph is displayed according to the Filters defined on another component.
  My issue is that when searching with new parameters I can't seem to clean the previous chart and I was wondering if someone could help me. Basically what I'm having right now is, when I first enter the page, the loading component, then I have my graph and when I search for a new date I have the loading component but on top of that I still have the previous graph</p>
  <p>I figured I could use <code>flamegraph().destroy()</code> on <code>const updateGraph</code> but nothing is happening</p>
  <pre><code>import React, { FC, useEffect, useRef, useState, useCallback } from 'react'
  import { useParams } from 'react-router-dom'
  import moment from 'moment'
  import * as d3 from 'd3'
  import { flamegraph } from 'd3-flame-graph'
  
  import Filters, { Filter } from '../../../../../../components/Filters'
  import { getFlamegraph } from '../../../../../../services/flamegraph'
  import { useQueryFilter } from '../../../../../../hooks/filters'
  import FlamegraphPlaceholder from '../../../../../../components/Placeholders/Flamegraph'
  
  import css from './flamegraph.module.css'
  
  import ToastContainer, {
    useToastContainerMessage,
  } from '../../../../../../components/ToastContainer'
  
  const defaultFilters = {
    startDate: moment().subtract(1, 'month'),
    endDate: moment(),
    text: '',
    limit: 10,
  }
  
  const getOffSet = (divElement: HTMLDivElement | null) =&gt; {
    if (divElement !== null) {
      const padding = 100
      const minGraphHeight = 450
  
      // ensure that the graph has a min height
      return Math.max(
        window.innerHeight - divElement.offsetTop - padding,
        minGraphHeight
      )
    } else {
      const fallBackNavigationHeight = 300
  
      return window.innerHeight - fallBackNavigationHeight
    }
  }
  
  const Flamegraph: FC = () =&gt; {
    const [queryFilters, setQueryFilters] = useQueryFilter(defaultFilters)
    const [fetching, setFetching] = useState(false)
    const [graphData, setGraphData] = useState()
    const {
      messages: toastMessages,
      addMessage: addMessageToContainer,
      removeMessage: removeMessageFromContainer,
    } = useToastContainerMessage()
    const flameContainerRef = useRef&lt;HTMLDivElement | null&gt;(null)
    const flameRef = useRef&lt;HTMLDivElement | null&gt;(null)
    const graphRef = useRef&lt;any&gt;()
    const graphDataRef = useRef&lt;any&gt;()
    const timerRef = useRef&lt;any&gt;()
  
    const { projectId, functionId } = useParams()
    let [sourceId, sourceLine] = ['', '']
  
    if (functionId) {
      ;[sourceId, sourceLine] = functionId.split(':')
    }
  
    const createGraph = () =&gt; {
      if (flameContainerRef.current &amp;&amp; flameRef.current) {
        graphRef.current = flamegraph()
          .width(flameContainerRef.current.offsetWidth)
          .height(getOffSet(flameRef.current))
          .cellHeight(30)
          .tooltip(false)
          .setColorMapper(function(d, originalColor) {
            // Scale green component proportionally to box width (=&gt; the wider the redder)
            let greenHex = (192 - Math.round((d.x1 - d.x0) * 128)).toString(16)
            return '#FF' + ('0' + greenHex).slice(-2) + '00'
          })
      }
    }
  
    const updateGraph = (newData: any) =&gt; {
      setGraphData(newData)
      graphDataRef.current = newData
  
      if (graphRef.current) {
        if (newData === null) {
          graphRef.current.destroy()
          graphRef.current = null
        } else {
          d3.select(flameRef.current)
            .datum(newData)
            .call(graphRef.current)
        }
      }
    }
  
    const fetchGraph = (filters: Filter) =&gt; {
      setFetching(true)
      getFlamegraph(
        Number(projectId),
        filters.startDate ? filters.startDate.unix() : 0,
        filters.endDate ? filters.endDate.unix() : 0,
        sourceId,
        sourceLine
      )
        .then(graphData =&gt; {
          if (!graphRef.current) {
            createGraph()
          }
          updateGraph(graphData)
        })
        .catch(({ response }) =&gt; {
          updateGraph(null)
          if (response.data) {
            addMessageToContainer(response.data.message, true)
          }
        })
        .finally(() =&gt; {
          setFetching(false)
        })
    }
  
    const onResize = useCallback(() =&gt; {
      clearTimeout(timerRef.current)
      timerRef.current = setTimeout(() =&gt; {
        if (graphRef.current &amp;&amp; flameContainerRef.current) {
          graphRef.current.width(flameContainerRef.current.offsetWidth)
          d3.select(flameRef.current)
            .datum(graphDataRef.current)
            .call(graphRef.current)
        }
      }, 500)
    }, [])
  
    useEffect(() =&gt; {
      fetchGraph(queryFilters)
      window.addEventListener('resize', onResize)
  
      return () =&gt; {
        window.removeEventListener('resize', onResize)
      }
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [])
  
    const onChangeFilters = (filters: Filter) =&gt; {
      setQueryFilters(filters)
      fetchGraph(filters)
    }
  
    return (
      &lt;div className={css.host}&gt;
        &lt;Filters
          defaultValues={queryFilters}
          searching={fetching}
          onSearch={onChangeFilters}
        /&gt;
        &lt;div className={css.flameBox}&gt;
          &lt;div className={css.flameContainer} ref={flameContainerRef}&gt;
            &lt;div ref={flameRef} /&gt;
          &lt;/div&gt;
          {fetching || !graphData ? (
            &lt;FlamegraphPlaceholder loading={fetching} /&gt;
          ) : null}
        &lt;/div&gt;
        &lt;ToastContainer
          messages={toastMessages}
          toastDismissed={removeMessageFromContainer}
        /&gt;
      &lt;/div&gt;
    )
  }
  
  export default Flamegraph
  </code></pre>