{"id":13139,"date":"2025-08-14T11:18:17","date_gmt":"2025-08-14T11:18:17","guid":{"rendered":"https:\/\/www.bacancytechnology.com\/qanda\/?p=13139"},"modified":"2025-08-14T11:18:17","modified_gmt":"2025-08-14T11:18:17","slug":"display-api-data-in-line-charts-with-react-chartjs-2","status":"publish","type":"post","link":"https:\/\/www.bacancytechnology.com\/qanda\/react\/display-api-data-in-line-charts-with-react-chartjs-2","title":{"rendered":"How to Display API Data in Line Charts Using react-chartjs-2"},"content":{"rendered":"<p>If we&#8217;re working with the Quickbase API and want to visualize the returned data using react-chartjs-2, we&#8217;re in the right place. One common use case is to display numerical job-related fields (like costs, durations, etc.) over time or by project\/job title using a line chart.<\/p>\n<p>Below, we\u2019ll walk through:<\/p>\n<ul>\n<li>How to correctly fetch and format Quickbase API data<\/li>\n<li>How to transform that data for a line chart&lt;\/li<\/li>\n<li>How to display it dynamically using Chart.js (through react-chartjs-2)<\/li>\n<\/ul>\n<h3>Class component:<\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"r\">import React, { Component } from 'react';\r\nimport { Line } from 'react-chartjs-2';\r\nimport {\r\n  Chart as ChartJS,\r\n  LineElement,\r\n  CategoryScale,\r\n  LinearScale,\r\n  PointElement,\r\n  Tooltip,\r\n  Legend,\r\n} from 'chart.js';\r\nChartJS.register(\r\n  LineElement,\r\n  CategoryScale,\r\n  LinearScale,\r\n  PointElement,\r\n  Tooltip,\r\n  Legend\r\n);\r\nconst headers = {\r\n  'QB-Realm-Hostname': 'YOUR_REALM.quickbase.com',\r\n  'User-Agent': 'FileService_Integration_V2.1',\r\n  'Authorization': 'QB-USER-TOKEN YOUR_TOKEN',\r\n  'Content-Type': 'application\/json',\r\n};\r\nclass TotalLineChart extends Component {\r\n  constructor(props) {\r\n    super(props);\r\n    this.state = {\r\n      chartData: null,\r\n    };\r\n  }\r\n  componentDidMount() {\r\n    this.fetchData();\r\n  }\r\n  fetchData = () =&gt; {\r\n    const body = {\r\n      from: 'bpz99ram7',\r\n      select: [3, 6, 80], \/\/ 3 = Job ID, 6 = Title, 80 = Cost (example)\r\n      where: \"{40.CT. 'In Progress'}\", \/\/ Filter for jobs in progress\r\n      sortBy: [{ fieldId: 6, order: 'ASC' }],\r\n      options: { skip: 0, top: 0 },\r\n    };\r\n\r\n    fetch('https:\/\/api.quickbase.com\/v1\/records\/query', {\r\n      method: 'POST',\r\n      headers: headers,\r\n      body: JSON.stringify(body),\r\n    })\r\n      .then((response) =&gt; response.json())\r\n      .then((data) =&gt; this.prepareChartData(data))\r\n      .catch((error) =&gt; console.error('API fetch error:', error));\r\n  };\r\n\r\n  prepareChartData = (apiResponse) =&gt; {\r\n    const records = apiResponse.data;\r\n\r\n    \/\/ Extract labels (e.g., Job Titles)\r\n    const labels = records.map((record) =&gt; record['6']?.value || 'No Title');\r\n\r\n    \/\/ Extract data points (e.g., Job Costs)\r\n    const dataPoints = records.map((record) =&gt; record['80']?.value || 0);\r\n\r\n    const chartData = {\r\n      labels,\r\n      datasets: [\r\n        {\r\n          label: 'Job Cost',\r\n          data: dataPoints,\r\n          fill: false,\r\n          borderColor: '#00498D',\r\n          tension: 0.2,\r\n        },\r\n      ],\r\n    };\r\n\r\n    this.setState({ chartData });\r\n  };\r\n  render() {\r\n    const { chartData } = this.state;\r\n\r\n    if (!chartData) return &lt;div&gt;Loading chart...&lt;\/div&gt;;\r\n\r\n    const options = {\r\n      responsive: true,\r\n      plugins: {\r\n        legend: { position: 'top' },\r\n      },\r\n      scales: {\r\n        y: {\r\n          beginAtZero: true,\r\n        },\r\n      },\r\n    };\r\n\r\n    return (\r\n      &lt;div style={{ width: '90%', margin: '0 auto' }}&gt;\r\n        &lt;h2&gt;Line Chart - Job Cost by Title&lt;\/h2&gt;\r\n        &lt;Line data={chartData} options={options} \/&gt;\r\n      &lt;\/div&gt;\r\n    );\r\n  }\r\n}\r\nexport default TotalLineChart;\r\n<\/pre>\n<p>Here is also a functional component example: (Code snippet compatible for React version 18+)<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"r\">\r\nimport React, { useEffect, useState } from 'react';\r\nimport { Line } from 'react-chartjs-2';\r\nimport {\r\n  Chart as ChartJS,\r\n  LineElement,\r\n  CategoryScale,\r\n  LinearScale,\r\n  PointElement,\r\n  Tooltip,\r\n  Legend,\r\n} from 'chart.js';\r\n\r\nChartJS.register(\r\n  LineElement,\r\n  CategoryScale,\r\n  LinearScale,\r\n  PointElement,\r\n  Tooltip,\r\n  Legend\r\n);\r\n\r\nconst headers = {\r\n  'QB-Realm-Hostname': 'YOUR_REALM.quickbase.com',\r\n  'User-Agent': 'FileService_Integration_V2.1',\r\n  'Authorization': 'QB-USER-TOKEN YOUR_TOKEN',\r\n  'Content-Type': 'application\/json',\r\n};\r\n\r\nconst TotalLineChart = () => {\r\n  const [chartData, setChartData] = useState(null);\r\n\r\n  useEffect(() => {\r\n    const fetchData = async () => {\r\n      const body = {\r\n        from: 'bpz99ram7',\r\n        select: [3, 6, 80], \/\/ 3 = Job ID, 6 = Title, 80 = Cost (example)\r\n        where: \"{40.CT. 'In Progress'}\",\r\n        sortBy: [{ fieldId: 6, order: 'ASC' }],\r\n        options: { skip: 0, top: 0 },\r\n      };\r\n\r\n      try {\r\n        const response = await fetch('https:\/\/api.quickbase.com\/v1\/records\/query', {\r\n          method: 'POST',\r\n          headers,\r\n          body: JSON.stringify(body),\r\n        });\r\n\r\n        const data = await response.json();\r\n        prepareChartData(data);\r\n      } catch (error) {\r\n        console.error('API fetch error:', error);\r\n      }\r\n    };\r\n\r\n    const prepareChartData = (apiResponse) => {\r\n      const records = apiResponse.data;\r\n      const labels = records.map((record) => record['6']?.value || 'No Title');\r\n      const dataPoints = records.map((record) => record['80']?.value || 0);\r\n\r\n      setChartData({\r\n        labels,\r\n        datasets: [\r\n          {\r\n            label: 'Job Cost',\r\n            data: dataPoints,\r\n            fill: false,\r\n            borderColor: '#00498D',\r\n            tension: 0.2,\r\n          },\r\n        ],\r\n      });\r\n    };\r\n\r\n    fetchData();\r\n  }, []);\r\n\r\n  const options = {\r\n    responsive: true,\r\n    plugins: {\r\n      legend: { position: 'top' },\r\n    },\r\n    scales: {\r\n      y: {\r\n        beginAtZero: true,\r\n      },\r\n    },\r\n  };\r\n\r\n  return (\r\n    <div style={{ width: '90%', margin: '0 auto' }}>\r\n      <h2>Line Chart - Job Cost by Title<\/h2>\r\n      {chartData ? (\r\n        <Line data={chartData} options={options} \/>\r\n      ) : (\r\n        <div>Loading chart...<\/div>\r\n      )}\r\n    <\/div>\r\n  );\r\n};\r\n\r\nexport default TotalLineChart;\r\n<\/pre>\n<p>What&#8217;s Happening Here?<\/p>\n<p><strong>API Call:<\/strong> Fetches job records filtered by status = &#8220;In Progress&#8221;.<\/p>\n<h3>Field IDs:<\/hw3><\/p>\n<ul>\n<li>6: Title or job name.<\/li>\n<li>80: Example field representing job cost.<\/li>\n<\/ul>\n<p><strong>Transforming Data:<\/strong> We map the response to extract an array of labels and values for Chart.js.<\/p>\n<p><strong>Line Chart Display:<\/strong> Each job title is plotted with its corresponding cost.<\/p>\n<p><strong>This post showed how to:<\/strong><\/p>\n<ul>\n<li>Connect to Quickbase API,<\/li>\n<li>Parse the response,<\/li>\n<li>Format it for a line chart using react-chartjs-2,<\/li>\n<li>Fix common issues with rendering chart data.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>If we&#8217;re working with the Quickbase API and want to visualize the returned data using react-chartjs-2, we&#8217;re in the right place. One common use case is to display numerical job-related fields (like costs, durations, etc.) over time or by project\/job title using a line chart. Below, we\u2019ll walk through: How to correctly fetch and format [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":13141,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-13139","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-react"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/posts\/13139"}],"collection":[{"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/comments?post=13139"}],"version-history":[{"count":2,"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/posts\/13139\/revisions"}],"predecessor-version":[{"id":13142,"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/posts\/13139\/revisions\/13142"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/media\/13141"}],"wp:attachment":[{"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/media?parent=13139"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/categories?post=13139"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/qanda\/wp-json\/wp\/v2\/tags?post=13139"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}