Hello Retool Community,
Your charts are great but I am trying to use custom components that uses Highcharts for further customization.
But the custom component got re-rendered every time when I press
I added logging to see what's going on apparently it got re-rendered every time I press shift, control or cmd. How to prevent this?
Attached is the source code of the custom component.
import { type FC, useRef, useEffect } from 'react'
import Highcharts from 'highcharts'
import { Retool } from '@tryretool/custom-component-support'
export const BarChart: FC = () => {
const chartContainerRef = useRef<HTMLDivElement>(null)
const [data, setData] = Retool.useStateArray({ name: 'data' })
const [categories, setCategories] = Retool.useStateArray({ name: 'categories' })
console.log("custom component called");
useEffect(() => {
if (chartContainerRef.current) {
const options: Highcharts.Options = {
chart: {
type: 'bar'
},
xAxis: {
categories: categories
},
series: [{ data }],
};
Highcharts.chart(chartContainerRef.current, options)
}
}, [data, categories]);
return <div ref={chartContainerRef} />
}
Check the video too for reference.
1 Like
in case you are trying to reproduce.
cc: @Jack_T @lindakwoo
Hey @abdulhamed , Welcome To Retool Community !
I can try this custom component code on my app. You're right—when I press any keyboard key, the chart refreshes or re-renders. I found a solution!
I've updated the custom component code with the following changes:
- Added
chartRef
to persist the Highcharts instance.
- Modified the
useEffect
logic to ensure the chart is only created once, and updated thereafter.
- Used
JSON.stringify
in the dependency array for a deep comparison.
const chartRef = useRef<Highcharts.Chart | null>(null) // Store chart instance
[JSON.stringify(data), JSON.stringify(categories)]); // Deep comparison to prevent unnecessary runs
import { type FC, useRef, useEffect } from 'react'
import Highcharts from 'highcharts'
import { Retool } from '@tryretool/custom-component-support'
export const BarChart: FC = () => {
const chartContainerRef = useRef<HTMLDivElement>(null)
const chartRef = useRef<Highcharts.Chart | null>(null) // Store chart instance
const [data, setData] = Retool.useStateArray({ name: 'data' })
const [categories, setCategories] = Retool.useStateArray({ name: 'categories' })
console.log("custom component called");
useEffect(() => {
if (chartContainerRef.current) {
const options: Highcharts.Options = {
chart: {
type: 'bar'
},
xAxis: {
categories: categories
},
series: [{ data }],
};
if (!chartRef.current) {
// Create chart only if it doesn’t exist
chartRef.current = Highcharts.chart(chartContainerRef.current, options)
} else {
// Update existing chart instead of recreating
chartRef.current.update(options, true)
}
}
// Cleanup on unmount
return () => {
if (chartRef.current) {
chartRef.current.destroy()
chartRef.current = null
}
}
}, [JSON.stringify(data), JSON.stringify(categories)]); // Deep comparison to prevent unnecessary runs
return <div ref={chartContainerRef} />
}
6 Likes
life-saving! Thanks man appreciate it
1 Like