{"id":30019,"date":"2026-04-17T05:49:38","date_gmt":"2026-04-17T05:49:38","guid":{"rendered":"urn:uuid:e81192b3-e6a0-4300-adeb-391f46f18a6f"},"modified":"2026-04-17T08:18:11","modified_gmt":"2026-04-17T08:18:11","slug":"dynamic-charts-in-react-using-usestate-with-highcharts-react","status":"publish","type":"post","link":"https:\/\/www.highcharts.com\/blog\/post\/dynamic-charts-in-react-using-usestate-with-highcharts-react\/","title":{"rendered":"Dynamic Charts in React using useState with @highcharts\/react"},"content":{"rendered":"<p>Building a chart that responds to data changes is a useful tool to know. In this post, I will show you how to connect <code>@highcharts\/react<\/code> to React state so your chart updates automatically with no manual refresh, no <code>chart.update()<\/code> call, just React doing what it does best.<\/p>\n\n\n<h2 class=\"wp-block-heading\">What you will build<\/h2>\n\n\n\n<p>A line chart that updates instantly when the underlying data changes. Simple, clean, and the foundation for every real dashboard you will ever build.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Node.js installed (<code>node -v<\/code> to check)<\/li>\n\n\n\n<li>Basic knowledge of React<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Setting up the project<\/h2>\n\n\n\n<p>Create a folder, then create a new React project using Vite:<\/p>\n\n\n\n<div class=\"wp-block-group is-vertical is-layout-flex wp-container-core-group-is-layout-fe9cc265 wp-block-group-is-layout-flex\">\n<div class=\"hs-code-outer-container\"><div class=\"hs-code-container neutral-50-light neutral-800-dark\" tabindex=\"0\" role=\"region\" aria-label=\"Code block\">\n<pre class=\"wp-block-code\"><code>npm create vite@latest . -- --template react<\/code><\/pre>\n\n\n\n<div class=\"wp-block-highsoft-hs-button\"><button type=\"button\" class=\"hc-button hc-button--white hc-button--size-200\" data-copy-code=\"true\" aria-label=\"Copy\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" fill=\"none\" viewBox=\"0 0 24 24\" width=\"16\" height=\"16\"><path stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 8V5.2c0-1.12 0-1.68.218-2.108a2 2 0 0 1 .874-.874C9.52 2 10.08 2 11.2 2h7.6c1.12 0 1.68 0 2.108.218a2 2 0 0 1 .874.874C22 3.52 22 4.08 22 5.2v7.6c0 1.12 0 1.68-.218 2.108a2 2 0 0 1-.874.874C20.48 16 19.92 16 18.8 16H16M5.2 22h7.6c1.12 0 1.68 0 2.108-.218a2 2 0 0 0 .874-.874C16 20.48 16 19.92 16 18.8v-7.6c0-1.12 0-1.68-.218-2.108a2 2 0 0 0-.874-.874C14.48 8 13.92 8 12.8 8H5.2c-1.12 0-1.68 0-2.108.218a2 2 0 0 0-.874.874C2 9.52 2 10.08 2 11.2v7.6c0 1.12 0 1.68.218 2.108a2 2 0 0 0 .874.874C3.52 22 4.08 22 5.2 22\"><\/path><\/svg>Copy<\/button><\/div>\n<\/div><\/div>\n<\/div>\n\n\n\n<p>Install Highcharts:<\/p>\n\n\n\n<div class=\"wp-block-group is-vertical is-layout-flex wp-container-core-group-is-layout-fe9cc265 wp-block-group-is-layout-flex\">\n<div class=\"hs-code-outer-container\"><div class=\"hs-code-container neutral-50-light neutral-800-dark\" tabindex=\"0\" role=\"region\" aria-label=\"Code block\">\n<pre class=\"wp-block-code\"><code>npm install @highcharts\/react<\/code><\/pre>\n\n\n\n<div class=\"wp-block-highsoft-hs-button\"><button type=\"button\" class=\"hc-button hc-button--white hc-button--size-200\" data-copy-code=\"true\" aria-label=\"Copy\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" fill=\"none\" viewBox=\"0 0 24 24\" width=\"16\" height=\"16\"><path stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 8V5.2c0-1.12 0-1.68.218-2.108a2 2 0 0 1 .874-.874C9.52 2 10.08 2 11.2 2h7.6c1.12 0 1.68 0 2.108.218a2 2 0 0 1 .874.874C22 3.52 22 4.08 22 5.2v7.6c0 1.12 0 1.68-.218 2.108a2 2 0 0 1-.874.874C20.48 16 19.92 16 18.8 16H16M5.2 22h7.6c1.12 0 1.68 0 2.108-.218a2 2 0 0 0 .874-.874C16 20.48 16 19.92 16 18.8v-7.6c0-1.12 0-1.68-.218-2.108a2 2 0 0 0-.874-.874C14.48 8 13.92 8 12.8 8H5.2c-1.12 0-1.68 0-2.108.218a2 2 0 0 0-.874.874C2 9.52 2 10.08 2 11.2v7.6c0 1.12 0 1.68.218 2.108a2 2 0 0 0 .874.874C3.52 22 4.08 22 5.2 22\"><\/path><\/svg>Copy<\/button><\/div>\n<\/div><\/div>\n<\/div>\n\n\n\n<p>Start the dev server:<\/p>\n\n\n\n<div class=\"wp-block-group is-vertical is-layout-flex wp-container-core-group-is-layout-fe9cc265 wp-block-group-is-layout-flex\">\n<div class=\"hs-code-outer-container\"><div class=\"hs-code-container neutral-50-light neutral-800-dark\" tabindex=\"0\" role=\"region\" aria-label=\"Code block\">\n<pre class=\"wp-block-code\"><code>npm run dev<\/code><\/pre>\n\n\n\n<div class=\"wp-block-highsoft-hs-button\"><button type=\"button\" class=\"hc-button hc-button--white hc-button--size-200\" data-copy-code=\"true\" aria-label=\"Copy\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" fill=\"none\" viewBox=\"0 0 24 24\" width=\"16\" height=\"16\"><path stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 8V5.2c0-1.12 0-1.68.218-2.108a2 2 0 0 1 .874-.874C9.52 2 10.08 2 11.2 2h7.6c1.12 0 1.68 0 2.108.218a2 2 0 0 1 .874.874C22 3.52 22 4.08 22 5.2v7.6c0 1.12 0 1.68-.218 2.108a2 2 0 0 1-.874.874C20.48 16 19.92 16 18.8 16H16M5.2 22h7.6c1.12 0 1.68 0 2.108-.218a2 2 0 0 0 .874-.874C16 20.48 16 19.92 16 18.8v-7.6c0-1.12 0-1.68-.218-2.108a2 2 0 0 0-.874-.874C14.48 8 13.92 8 12.8 8H5.2c-1.12 0-1.68 0-2.108.218a2 2 0 0 0-.874.874C2 9.52 2 10.08 2 11.2v7.6c0 1.12 0 1.68.218 2.108a2 2 0 0 0 .874.874C3.52 22 4.08 22 5.2 22\"><\/path><\/svg>Copy<\/button><\/div>\n<\/div><\/div>\n\n\n\n<p><\/p>\n<\/div>\n\n\n\n<p>Then open <code>http:\/\/localhost:5173<\/code> in yout browser.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Your first chart<\/h2>\n\n\n\n<p>Open src\/App.jsx, delete everything inside and replace it with:<\/p>\n\n\n\n<div class=\"wp-block-group is-vertical is-layout-flex wp-container-core-group-is-layout-fe9cc265 wp-block-group-is-layout-flex\">\n<div class=\"hs-code-outer-container\"><div class=\"hs-code-container neutral-50-light neutral-800-dark\" tabindex=\"0\" role=\"region\" aria-label=\"Code block\">\n<pre class=\"wp-block-code\"><code>import { Chart } from '@highcharts\/react'\nimport { LineSeries } from '@highcharts\/react\/series\/Line'\n\nfunction App() {\n&nbsp;&nbsp;return (\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;Chart&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;LineSeries data={&#91;3, 4, 1, 5, 2]} \/&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;\/Chart&gt;\n&nbsp;&nbsp;)\n}\nexport default App<\/code><\/pre>\n\n\n\n<div class=\"wp-block-highsoft-hs-button\"><button type=\"button\" class=\"hc-button hc-button--white hc-button--size-200\" data-copy-code=\"true\" aria-label=\"Copy\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" fill=\"none\" viewBox=\"0 0 24 24\" width=\"16\" height=\"16\"><path stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 8V5.2c0-1.12 0-1.68.218-2.108a2 2 0 0 1 .874-.874C9.52 2 10.08 2 11.2 2h7.6c1.12 0 1.68 0 2.108.218a2 2 0 0 1 .874.874C22 3.52 22 4.08 22 5.2v7.6c0 1.12 0 1.68-.218 2.108a2 2 0 0 1-.874.874C20.48 16 19.92 16 18.8 16H16M5.2 22h7.6c1.12 0 1.68 0 2.108-.218a2 2 0 0 0 .874-.874C16 20.48 16 19.92 16 18.8v-7.6c0-1.12 0-1.68-.218-2.108a2 2 0 0 0-.874-.874C14.48 8 13.92 8 12.8 8H5.2c-1.12 0-1.68 0-2.108.218a2 2 0 0 0-.874.874C2 9.52 2 10.08 2 11.2v7.6c0 1.12 0 1.68.218 2.108a2 2 0 0 0 .874.874C3.52 22 4.08 22 5.2 22\"><\/path><\/svg>Copy<\/button><\/div>\n<\/div><\/div>\n<\/div>\n\n\n\n<p>Save the file. You should see a line chart in your browser.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Adding useState<\/strong><\/h2>\n\n\n\n<p>Static data is a good start. But real dashboards have dynamic data, filters, user interactions, API responses. This is where useState comes in.<\/p>\n\n\n\n<p>useState gives your component memory. When the data changes, React re-renders the component and the chart reflects the new data automatically.<\/p>\n\n\n\n<p>Update App.jsx:<\/p>\n\n\n\n<div class=\"wp-block-group is-vertical is-layout-flex wp-container-core-group-is-layout-fe9cc265 wp-block-group-is-layout-flex\">\n<div class=\"hs-code-outer-container\"><div class=\"hs-code-container neutral-50-light neutral-800-dark\" tabindex=\"0\" role=\"region\" aria-label=\"Code block\">\n<pre class=\"wp-block-code\"><code>import { useState } from 'react'\nimport { Chart } from '@highcharts\/react'\nimport { LineSeries } from '@highcharts\/react\/series\/Line'\n\nfunction App() {\n\u00a0const &#91;data, setData] = useState(&#91;3, 4, 1, 5, 2])\n\u00a0function updateData() {\n\u00a0\u00a0\u00a0setData(&#91;5, 2, 8, 1, 6])\n\u00a0}\n\u00a0return (\n\u00a0\u00a0\u00a0&lt;>\n\u00a0\u00a0\u00a0\u00a0\u00a0&lt;button onClick={updateData}>Update Chart&lt;\/button>\n\u00a0\u00a0\u00a0\u00a0\u00a0&lt;Chart>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;LineSeries data={data} \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/Chart>\n\u00a0\u00a0\u00a0&lt;\/>\n\u00a0)\n}\nexport default App<\/code><\/pre>\n\n\n\n<div class=\"wp-block-highsoft-hs-button\"><button type=\"button\" class=\"hc-button hc-button--white hc-button--size-200\" data-copy-code=\"true\" aria-label=\"Copy\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" fill=\"none\" viewBox=\"0 0 24 24\" width=\"16\" height=\"16\"><path stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 8V5.2c0-1.12 0-1.68.218-2.108a2 2 0 0 1 .874-.874C9.52 2 10.08 2 11.2 2h7.6c1.12 0 1.68 0 2.108.218a2 2 0 0 1 .874.874C22 3.52 22 4.08 22 5.2v7.6c0 1.12 0 1.68-.218 2.108a2 2 0 0 1-.874.874C20.48 16 19.92 16 18.8 16H16M5.2 22h7.6c1.12 0 1.68 0 2.108-.218a2 2 0 0 0 .874-.874C16 20.48 16 19.92 16 18.8v-7.6c0-1.12 0-1.68-.218-2.108a2 2 0 0 0-.874-.874C14.48 8 13.92 8 12.8 8H5.2c-1.12 0-1.68 0-2.108.218a2 2 0 0 0-.874.874C2 9.52 2 10.08 2 11.2v7.6c0 1.12 0 1.68.218 2.108a2 2 0 0 0 .874.874C3.52 22 4.08 22 5.2 22\"><\/path><\/svg>Copy<\/button><\/div>\n<\/div><\/div>\n<\/div>\n\n\n\n<p>Click the button. The chart updates instantly.<br><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"760\" height=\"315\" src=\"https:\/\/www.highcharts.com\/blog\/wp-content\/uploads\/2026\/04\/Screenshot-2026-04-14-at-13.02.53-1-760x315.jpg\" alt=\"\" class=\"wp-image-30026\" srcset=\"https:\/\/www.highcharts.com\/blog\/wp-content\/uploads\/2026\/04\/Screenshot-2026-04-14-at-13.02.53-1-760x315.jpg 760w, https:\/\/www.highcharts.com\/blog\/wp-content\/uploads\/2026\/04\/Screenshot-2026-04-14-at-13.02.53-1-560x232.jpg 560w, https:\/\/www.highcharts.com\/blog\/wp-content\/uploads\/2026\/04\/Screenshot-2026-04-14-at-13.02.53-1-768x318.jpg 768w, https:\/\/www.highcharts.com\/blog\/wp-content\/uploads\/2026\/04\/Screenshot-2026-04-14-at-13.02.53-1.jpg 790w\" sizes=\"auto, (max-width: 760px) 100vw, 760px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">What just happened<\/h2>\n\n\n\n<p>Three things worth understanding:<\/p>\n\n\n\n<p><strong>1. <\/strong><strong>useState<\/strong><strong> initialises the data<\/strong><\/p>\n\n\n\n<div class=\"wp-block-group is-vertical is-layout-flex wp-container-core-group-is-layout-fe9cc265 wp-block-group-is-layout-flex\">\n<div class=\"hs-code-outer-container\"><div class=\"hs-code-container neutral-50-light neutral-800-dark\" tabindex=\"0\" role=\"region\" aria-label=\"Code block\">\n<pre class=\"wp-block-code\"><code>const &#91;data, setData] = useState(&#91;3, 4, 1, 5, 2])<\/code><\/pre>\n\n\n\n<div class=\"wp-block-highsoft-hs-button\"><button type=\"button\" class=\"hc-button hc-button--white hc-button--size-200\" data-copy-code=\"true\" aria-label=\"Copy\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" fill=\"none\" viewBox=\"0 0 24 24\" width=\"16\" height=\"16\"><path stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 8V5.2c0-1.12 0-1.68.218-2.108a2 2 0 0 1 .874-.874C9.52 2 10.08 2 11.2 2h7.6c1.12 0 1.68 0 2.108.218a2 2 0 0 1 .874.874C22 3.52 22 4.08 22 5.2v7.6c0 1.12 0 1.68-.218 2.108a2 2 0 0 1-.874.874C20.48 16 19.92 16 18.8 16H16M5.2 22h7.6c1.12 0 1.68 0 2.108-.218a2 2 0 0 0 .874-.874C16 20.48 16 19.92 16 18.8v-7.6c0-1.12 0-1.68-.218-2.108a2 2 0 0 0-.874-.874C14.48 8 13.92 8 12.8 8H5.2c-1.12 0-1.68 0-2.108.218a2 2 0 0 0-.874.874C2 9.52 2 10.08 2 11.2v7.6c0 1.12 0 1.68.218 2.108a2 2 0 0 0 .874.874C3.52 22 4.08 22 5.2 22\"><\/path><\/svg>Copy<\/button><\/div>\n<\/div><\/div>\n<\/div>\n\n\n\n<p>data holds the current value. setData updates it. Every time setData is called, React re-renders the component.<\/p>\n\n\n\n<p><strong>2. The chart receives data as a prop<\/strong><\/p>\n\n\n\n<div class=\"wp-block-group is-vertical is-layout-flex wp-container-core-group-is-layout-fe9cc265 wp-block-group-is-layout-flex\">\n<div class=\"hs-code-outer-container\"><div class=\"hs-code-container neutral-50-light neutral-800-dark\" tabindex=\"0\" role=\"region\" aria-label=\"Code block\">\n<pre class=\"wp-block-code\"><code>&lt;LineSeries data={data} \/&gt;<\/code><\/pre>\n\n\n\n<div class=\"wp-block-highsoft-hs-button\"><button type=\"button\" class=\"hc-button hc-button--white hc-button--size-200\" data-copy-code=\"true\" aria-label=\"Copy\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" fill=\"none\" viewBox=\"0 0 24 24\" width=\"16\" height=\"16\"><path stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 8V5.2c0-1.12 0-1.68.218-2.108a2 2 0 0 1 .874-.874C9.52 2 10.08 2 11.2 2h7.6c1.12 0 1.68 0 2.108.218a2 2 0 0 1 .874.874C22 3.52 22 4.08 22 5.2v7.6c0 1.12 0 1.68-.218 2.108a2 2 0 0 1-.874.874C20.48 16 19.92 16 18.8 16H16M5.2 22h7.6c1.12 0 1.68 0 2.108-.218a2 2 0 0 0 .874-.874C16 20.48 16 19.92 16 18.8v-7.6c0-1.12 0-1.68-.218-2.108a2 2 0 0 0-.874-.874C14.48 8 13.92 8 12.8 8H5.2c-1.12 0-1.68 0-2.108.218a2 2 0 0 0-.874.874C2 9.52 2 10.08 2 11.2v7.6c0 1.12 0 1.68.218 2.108a2 2 0 0 0 .874.874C3.52 22 4.08 22 5.2 22\"><\/path><\/svg>Copy<\/button><\/div>\n<\/div><\/div>\n<\/div>\n\n\n\n<p>data is just a prop. When it changes, @highcharts\/react handles the update internally,&nbsp; no manual intervention needed.<\/p>\n\n\n\n<p><strong>3. Don&#8217;t call <\/strong><strong>chart.update() <\/strong><strong>manually<\/strong> If you have used Highcharts before, chart.update() is still there, it happens behind the scenes every time your state changes. The integration is smart enough to call it at the right moment with the right options.<\/p>\n\n\n\n<p>What you should not do is call <code>chart.update()<\/code> manually. If you do, your React state and your chart will get out of sync, two sources of truth, neither reliable. Let the integration handle it. Update your state, and <code>@highcharts\/react<\/code> takes care of the rest.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why this matters<\/h2>\n\n\n\n<p>This is the pattern behind every dashboard filter, every date range picker, every data refresh button. The chart is not a special case in your component tree, it is just another React component that responds to state like everything else.In the next post, we will fetch real data from an API using useEffect and pass it through the same pattern.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Building a chart that responds to data changes is a useful tool to know. In this post, I will show you how to connect @highcharts\/react to React state so your chart updates automatically with no manual refresh, no chart.update() call, just React doing what it does best. What you will build A line chart that [&hellip;]<\/p>\n","protected":false},"author":32,"featured_media":30095,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"meta_title":"Dynamic Charts in React using useState with @highcharts\/react","meta_description":"Learn how to build dynamic charts in React using useState and @highcharts\/react. Update your chart automatically when state changes, no chart.update() needed","hc_selected_options":[],"footnotes":""},"categories":[224],"tags":[824,1111],"coauthors":[699],"class_list":["post-30019","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-post","tag-react","tag-usestate"],"_links":{"self":[{"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/posts\/30019","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/users\/32"}],"replies":[{"embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/comments?post=30019"}],"version-history":[{"count":3,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/posts\/30019\/revisions"}],"predecessor-version":[{"id":30104,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/posts\/30019\/revisions\/30104"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/media\/30095"}],"wp:attachment":[{"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/media?parent=30019"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/categories?post=30019"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/tags?post=30019"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/coauthors?post=30019"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}