<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ReactGrid</title>
    <description>The latest articles on DEV Community by ReactGrid (@reactgrid).</description>
    <link>https://dev.to/reactgrid</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F3262%2Fb7b0822e-cb95-4a21-bbdd-a2d5c9cd1f1b.png</url>
      <title>DEV Community: ReactGrid</title>
      <link>https://dev.to/reactgrid</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/reactgrid"/>
    <language>en</language>
    <item>
      <title>Financial liquidity planner with ReactGrid and Chart.js</title>
      <dc:creator>Patryk Eliasz</dc:creator>
      <pubDate>Mon, 08 Mar 2021 10:43:13 +0000</pubDate>
      <link>https://dev.to/reactgrid/financial-liquidity-planner-with-reactgrid-and-chart-js-44ii</link>
      <guid>https://dev.to/reactgrid/financial-liquidity-planner-with-reactgrid-and-chart-js-44ii</guid>
      <description>&lt;p&gt;We made &lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=planner"&gt;ReactGrid&lt;/a&gt; to compose your view with arbitrary cell order. In many components and tools in React ecosystem you have to keep the same data schema in all rows. Our component breaks out from the frame. You can add it to your project simply by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i @silevis/reactgrid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even if you don't need it in your project right now, you can leave a ⭐ in our &lt;a href="https://github.com/silevis/reactgrid"&gt;Github project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Today we will show you how to build a liquidity planner - an app that provides a strategy for financial planning in a long term. Our app will provide entering, aggregating, and evaluating planned cash flows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qJuVr6e3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1615193964210/ezKVuaGyf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qJuVr6e3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1615193964210/ezKVuaGyf.gif" alt="finished-app.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the Internet, you can find many spreadsheets files that e.g. accountants and financial analysts use - one of them, as an inspiration, will be moved from spreadsheet to standalone, fully &lt;strong&gt;reactive&lt;/strong&gt; React.js app.  We also visualize common parameters that help in decision-making with the Chart.js library.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is ReactGrid made for?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=planner"&gt;ReactGrid&lt;/a&gt; was designed to handle complex data displaying and editing in an arbitrary way. We depart from the rule of placing cells in the same order in every row - therefore you are able to add a spreadsheet-like experience to your React app.&lt;/p&gt;

&lt;p&gt;Liquidity planner is one of the many cases, in which 90% of React data table components usage is insufficient to recreate the expected look and feel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TNNp8LGH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ovbz3st9kkqba3e7k2q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TNNp8LGH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ovbz3st9kkqba3e7k2q.png" alt="reactgrid-use-cases.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Planning app with ReactGrid
&lt;/h2&gt;

&lt;p&gt;Before we start coding, we will talk about good practices that help to make predictable apps. Obviously, it's a good idea to apply them in all projects:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Separate the data from ReactGrid&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The main concept of &lt;strong&gt;reactivity&lt;/strong&gt; is updating your view every time your data changes. Very often we have no influence on the data structure, but we can map it to the structure that is the most convenient for us.  Before the data becomes acceptable by &lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=planner"&gt;ReactGrid&lt;/a&gt; or Chart.js we have to calculate a few variables in a repeatable way. This data lives only “for a moment” and should be independent from data and ReactGrid internal interfaces like &lt;code&gt;Column&lt;/code&gt; and &lt;code&gt;Row&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ReactGrid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Row&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@silevis/reactgrid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setRows&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;getReactGridRows&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ReactGrid&lt;/span&gt;
      &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;...{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Apply changes directly to the data&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=planner"&gt;ReactGrid&lt;/a&gt; contains its own encapsulated state to manage many background functionalities, like virtual scrolling or rendering optimizations. This state is based on &lt;code&gt;rows&lt;/code&gt; and &lt;code&gt;columns&lt;/code&gt; - two necessary ReactGrid props. ReactGrid is read-only until you define your own changes handling function, but a good practice is to update data at its source. After that the cycle of &lt;strong&gt;reactivity&lt;/strong&gt; concept is complete.&lt;/p&gt;

&lt;p&gt;Be aware of updating data that is directly related with ReactGrid interfaces ⚠️&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ReactGrid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CellChange&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@silevis/reactgrid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setRows&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;getReactGridRows&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleChanges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CellChange&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;setRows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
      &lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ReactGrid&lt;/span&gt;
      &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;onCellsChanged&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleChanges&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Use Typescript wherever it is possible&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Typescript prevents us from possible bugs at runtime. We encourage you to use it, especially with &lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=planner"&gt;ReactGrid&lt;/a&gt;. For cell templating reasons we introduced a few types of how the cell templating engine interfaces with ReactGrid. Thanks to this, you can safely transfer data between incompatible cells while interacting with them using the cell editor or, for example, pasting data from external sources or even other spreadsheets.&lt;/p&gt;

&lt;p&gt;A concrete example will be shown in the next chapter, but for now, take a look at the tiny example of Typescript &lt;a href="https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminating-unions"&gt;discriminating unions&lt;/a&gt;. Implemented in ReactGrid, &lt;code&gt;CellChange&lt;/code&gt;interface &lt;code&gt;type&lt;/code&gt; field allows you to ensure that the &lt;code&gt;checked&lt;/code&gt; field on &lt;code&gt;newCell&lt;/code&gt; really exists.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CellChange&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@silevis/reactgrid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleChanges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CellChange&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// evaluates as `CellChange&amp;lt;CheckboxCell&amp;gt;[] | CellChange&amp;lt;Datecell&amp;gt;[] | ...`&lt;/span&gt;
  &lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checkbox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newCell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previousCell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Compose your cell styling and behavior&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In most cases, you will use built-in cell templates like &lt;code&gt;NumberCell&lt;/code&gt; or &lt;code&gt;DateCell&lt;/code&gt;. ReactGrid allows you to style a cell and its behavior without introducing a new cell template, for example, "non-editable number cell with blue background". Instead, you can compose the functions as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;bottomLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;nonEditable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;showZero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numberCell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;yearlyGroupsDiff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-lg disabled font-bold&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Avoid merging metadata with cells&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since all of the cells have no idea where they are placed, it’s tempting to extend them with some metadata.  By metadata we mean the data that was added to ReactGrid related interfaces (e.g. &lt;code&gt;Row&lt;/code&gt;) by extending them with new attributes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt; &lt;span class="cm"&gt;/*
  * There should be no `isCollapsed` and `backgroundColor` metadata attributes
  */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Row&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isCollapsed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;backgroungColor&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;isCollapsed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;backgroungColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;rowId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Doe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also come across a similar situation that has arisen when some cells are related with each other - when building a tree list. Let’s have a look at the &lt;code&gt;ChevronCell&lt;/code&gt; interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ChevronCell&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Cell&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chevron&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;isExpanded&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;hasChildren&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;parentId&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Except for &lt;code&gt;parentId&lt;/code&gt; (which can actually be a row, column, or another cell) you can only control its look. There is no place declaring tree structure, dependencies between cells, or other data. We recommend extracting this metadata. The easiest way is to move this logic into a separate React hook that will contain those variables/data/logic.&lt;/p&gt;

&lt;p&gt;We will show you how to implement row toggling and working with tree-like structures in the next article.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does this planner do?
&lt;/h2&gt;

&lt;p&gt;We could debate financial issues for a long time, but there is not enough room for it so let's look at them in a nutshell. You can skip this chapter if you like.&lt;/p&gt;

&lt;p&gt;You can place a new value only in light green cells (credit line, opening balance) or with white background (cash inflows and outflows). Grayed-out cells are read-only.&lt;/p&gt;

&lt;p&gt;Two of them (opening balance and credit line) are just numbers. We merged types of cash flow into two. Each entry is called "group" and has its own title like "Travelling expenses" for outflow and "Sales" for inflow. Except for the title, all groups have an array of the amount of money spent/earned each month.&lt;/p&gt;

&lt;p&gt;Groups are aggregated vertically (inflows and outflows separately) into a total inflow or outflow per month. The last column presents all of the totals in a calendar year.&lt;/p&gt;

&lt;p&gt;"Cash in" and "Cash out" make up the "Total" row. This row and the other cells should update their content when sourcing data has changed or e.g. user typed a new value into the cell.&lt;/p&gt;

&lt;p&gt;Some items remain to be explained (and it's the hardest thing to understand): &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Cumulative row" takes cash in the bank, adds "Cash in" and then subtracts "Cash out".&lt;/li&gt;
&lt;li&gt;User can manipulate the value of a green cell "Cashbox/bank" and is called an "Opening balance". The rest of the cells in this row are filled automatically by moving already calculated value from the cumulative to the next month in the "Cashbox/bank".&lt;/li&gt;
&lt;li&gt;these operations are repeated until all months are filled.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TAGJtO-_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vzjqr1bgqppyxh79s9pl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TAGJtO-_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vzjqr1bgqppyxh79s9pl.png" alt="calculation-pseudo-algorithm-part-1.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The last part is the "Credit line". Users can update it by typing it in. This variable is constant for all months and is used for calculating "Credit line overdraft" - in a nutshell - if the absolute value from "Cumulative" exceeds the given credit line, then the cell should display this result.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k5I25hoR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ynqsr1nlx6qz6uqugq2u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k5I25hoR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ynqsr1nlx6qz6uqugq2u.png" alt="calculation-pseudo-algorithm-part-2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What about the chart? This part should give us an instant knowledge about the company's state of finance. In this case, we limit ourselves to display "Cashbox/bank" and "Credit Line Overdraft" as a line chart and cash inflow and outflow as bars.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some examples
&lt;/h2&gt;

&lt;p&gt;In the penultimate chapter, we discussed 5. tips for good app implementation with &lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=planner"&gt;ReactGrid&lt;/a&gt;. We will not discuss every line of code, but only code fragments in terms of the above-mentioned tips on how to work with ReactGrid.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Separate the data from ReactGrid&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;App component named &lt;code&gt;LiquidityPlanner&lt;/code&gt; has four React's &lt;code&gt;useState&lt;/code&gt; hooks, each of them stores part of raw financial data. E. g. &lt;code&gt;cashInflow&lt;/code&gt; is initiated with &lt;code&gt;emptyInflows&lt;/code&gt; that comes from the &lt;code&gt;rawData.ts&lt;/code&gt; file. This data has no connection with ReactGrid's interfaces and can be used directly by other components like charts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emptyMonthsValues&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inflows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CashInflow&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="c1"&gt;// ... &lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Other income&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;emptyMonthsValues&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// ... &lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Applying changes to the data&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ReactGrid runs your changes handler function when you interact with the data displayed by the grid. Each change is applied by dispatching &lt;code&gt;setCashInflow&lt;/code&gt;. To set updated inflows we used a technique called currying  (&lt;a href="https://javascript.info/currying-partials"&gt;more info&lt;/a&gt;), to apply particular &lt;code&gt;change&lt;/code&gt; on desired groups (&lt;code&gt;cashInflow&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CellChange&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NumberCell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ReactGrid&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@silevis/reactgrid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LiquidityPlanner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cashInflow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCashInflow&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;emptyInflows&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleChanges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CellChange&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;change&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CellChange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NumberCell&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// ...&lt;/span&gt;
      &lt;span class="nx"&gt;setCashInflow&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cashInflow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;applyChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;cashInflow&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ReactGrid&lt;/span&gt;
      &lt;span class="nx"&gt;onCellsChanged&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleChanges&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2tfkv_bd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fgqea5m3oxl1bdeaujdu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2tfkv_bd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fgqea5m3oxl1bdeaujdu.png" alt="reactivity-cycle.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Implementing changes handling in this way closes the reactivity cycle, therefore our task of processing input data into outputs is fully repeatable and has no side effects.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Typescript + ReactGrid = ❤️&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=planner"&gt;ReactGrid&lt;/a&gt; is built with Typescript and fully supports it. We also encourage you to use it in your projects. A real example from our app shows how we narrowed down the expected change object type exclusively to &lt;code&gt;NumberCell&lt;/code&gt;, therefore you are sure that you are able to access only actually existing fields.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleChanges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CellChange&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;change&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CellChange&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NumberCell&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rowId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;CASHBOXBANK_ROW_ID&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;columnId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;setOpeningBalance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newCell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rowId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;CREDITLINE_ROW_ID&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;columnId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;setCreditLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newCell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The other part is e. g. extending the set of built-in cell templates with your own. To be able to do it you have to pass the name of your custom Cell interface into a generic &lt;code&gt;CellChange&lt;/code&gt; interface.&lt;/p&gt;

&lt;p&gt;Of course, you are not obliged to move your project right now to Typescript, but we highly suggest using static typing.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Compose your cell styling and behavior&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you work with &lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=planner"&gt;ReactGrid&lt;/a&gt; it's highly possible that you will need to achieve the same or similar behavior or styling on many cells. The solution is quite simple - small, reusable functions. Familiarity with &lt;a href="https://reactgrid.com/docs?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=planner"&gt;documentation&lt;/a&gt; will definitely be useful.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;textCell&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;CellStyle&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;TextCell&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numberCell&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;CellStyle&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;NumberCell&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;numberFormat&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nonEditable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DefaultCellTypes&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;DefaultCellTypes&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;nonEditable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;showZero&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NumberCell&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;NumberCell&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;nanToZero&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;hideZero&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the usage: a function that uses mentioned functions to fill up the cells array in a single row.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getCashboxBankRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cashboxBank&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MonthlyValues&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Row&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;rowId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CASHBOXBANK_ROW_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ROW_HEIGHT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;nonEditable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;textCell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;padding-left-lg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;months&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
          &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;numberCell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cashboxBank&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;light-green-bg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;nonEditable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;showZero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numberCell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cashboxBank&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;disabled&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;nonEditable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;emptyTextCell&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Live demo
&lt;/h2&gt;

&lt;p&gt;We created a fully working liquidity planner example on &lt;a href="https://codesandbox.io/embed/reactgrid-liquidity-planner-526ps?fontsize=14&amp;amp;hidenavigation=1&amp;amp;module=%2Fsrc%2FLiquidityPlanner.tsx&amp;amp;theme=dark"&gt;codesandbox.io&lt;/a&gt;. &lt;br&gt;
This sample runs with the ReactGrid MIT, we encourage you to visit a &lt;a href="https://reactgrid.com/"&gt;fully functional sample&lt;/a&gt; deployed at our website. There you can try extra features available only in the PRO version: fill handle, range selection, area copy/cut/paste. You can compare both versions &lt;a href="https://reactgrid.com/feature-comparison?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=planner"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/reactgrid-liquidity-planner-526ps?module=%2Fsrc%2FLiquidityPlanner.tsx"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Liquidity planner is only one of many possible ReactGrid use cases when the standard data table is not enough.&lt;br&gt;
The main purpose of this article was to show you five useful tips that help you start the ReactGrid project using good practices.&lt;/p&gt;

&lt;p&gt;Don't forget to leave a ⭐ on our &lt;a href="https://github.com/silevis/reactgrid"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We encourage you to visit our official &lt;a href="https://reactgrid.com"&gt;ReactGrid website&lt;/a&gt;, &lt;br&gt;
where you will find the &lt;a href="https://reactgrid.com/docs?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=planner"&gt;documentation&lt;/a&gt; and information what the &lt;a href="https://reactgrid.com/feature-comparison?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=planner"&gt;PRO version&lt;/a&gt; of our component offers.&lt;/p&gt;

&lt;p&gt;Bye 👋&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>datagrid</category>
      <category>react</category>
    </item>
    <item>
      <title>How to build a table with concurrent horizontal and vertical sticky headers in pure CSS</title>
      <dc:creator>Kamil Mysłek</dc:creator>
      <pubDate>Mon, 18 Jan 2021 13:35:59 +0000</pubDate>
      <link>https://dev.to/reactgrid/how-to-build-a-table-with-concurrent-horizontal-and-vertical-sticky-headers-in-pure-css-25eg</link>
      <guid>https://dev.to/reactgrid/how-to-build-a-table-with-concurrent-horizontal-and-vertical-sticky-headers-in-pure-css-25eg</guid>
      <description>&lt;p&gt;While creating user interfaces, we often encounter the problem that there is more data in our tables than can be fitted in the visible viewport. To achieve &lt;br&gt;
an excellent user experience on components like Gannt charts, data tables and spreadsheets, we often use the sticky CSS property on the header elements. This is a simple task when doing it only on one edge of the table.&lt;/p&gt;

&lt;p&gt;But what if we want to display a huge table and therefore need sticky headers on more edges simultaneously? This is the exact problem we faced while building our &lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=blogcss"&gt;ReactGrid&lt;/a&gt; and in this article we want to share the solution we have found.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RHN0eZht--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ljp1ci0lt7lh0396blgr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RHN0eZht--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ljp1ci0lt7lh0396blgr.gif" alt="ReactGrid example with horizontal and vertical sticky headers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this guide, we will show you how to create the layout to achieve a native scroll behavior with sticky headers like those shown above &lt;strong&gt;without using any JavaScript.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What are the benefits of the proposed solution?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;native support from modern browsers,&lt;/li&gt;
&lt;li&gt;excellent user experience (intuitiveness, swiftness),&lt;/li&gt;
&lt;li&gt;additional elements in the scrollable view do not affect the UX,&lt;/li&gt;
&lt;li&gt;no JavaScript, only CSS and HTML,&lt;/li&gt;
&lt;li&gt;works perfectly on touch devices,&lt;/li&gt;
&lt;li&gt;avoids using z-index not to affect other elements on the website (needs z-index style values in Firefox with this solution).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You will learn how to place elements in the DOM and style them to achieve fully functional scrollable sticky panes using flexbox step by step. It's working and has been tested on the following browsers (remember, Firefox needs z-index style values).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zdTozLtn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jbu0oo61rqg9j7ibhuqi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zdTozLtn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jbu0oo61rqg9j7ibhuqi.png" alt="Supported browsers"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Placing Elements in the DOM using FlexBox
&lt;/h2&gt;

&lt;p&gt;The first and most important aspect is the correct order of the elements in the DOM because elements that appear later in the DOM will overlay other elements.&lt;/p&gt;

&lt;p&gt;Let's imagine that we want to create a layout with sticky headers on each edge. Therefore we need to divide our surface into 9 panes. Of course, the same procedure also applies to a smaller number of sticky edges.&lt;/p&gt;

&lt;p&gt;We place everything in two DIV tags. The first with overflow: auto CSS property to have a scrollable view. The second with the following CSS properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;position: relative;&lt;/li&gt;
&lt;li&gt;display: flex;&lt;/li&gt;
&lt;li&gt;flex-wrap: wrap;&lt;/li&gt;
&lt;li&gt;justify-content: flex-start;&lt;/li&gt;
&lt;li&gt;align-items: flex-start.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P5i8g5vM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/66v468e9r9z7f19flmx5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P5i8g5vM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/66v468e9r9z7f19flmx5.png" alt="Table with elements DOM positions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The graphic above illustrates the proper DOM order of the elements. The first element should be the one in the center of the layout, let's call it "middle-center-pane". It's the only DIV element which has a relative position in its CSS styles. The next elements, in order from the least to the most important, are bottom-center-pane, middle-right-pane, top-center-pane and midlle-left-pane. These elements have sticky positions in CSS styles. The same situation applies to the elements located in the corners of the view. We placed them in the order: bottom-right-pane, bottom-left-pane, top-right-pane, top-left-pane.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now we know in which order the panes should be placed to achieve the correct overlay behavior. However, we need more. For example, our top-left-pane is the last element in the DOM and will be rendered as the last one on the screen. What we need to do is to change the visual order of the elements. This can be achieved by using the CSS order property.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DVOGbOAz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fsnbv6wmkh9f60lzmhli.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DVOGbOAz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fsnbv6wmkh9f60lzmhli.png" alt="Table with helper arrow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's use the illustration above and place an arrow to help us sort the elements in the right order. We need to go from the top left corner to the bottom right corner. This will make it easier for us to create a table to define the CSS flex order property for our sticky header elements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q6pyjPAz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7pf1g5viicy8nmbhonak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q6pyjPAz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7pf1g5viicy8nmbhonak.png" alt="Table with sorted order values"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have created a solid basis to achieve the desired behavior. The panes are positioned in the right order and their overlay behavior is as expected. Now we need to set additional required CSS values for them. For our sticky header elements we should set &lt;strong&gt;position: sticky&lt;/strong&gt; and the proper &lt;strong&gt;top, right, left&lt;/strong&gt; and &lt;strong&gt;bottom&lt;/strong&gt; CSS values.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C1QoPseK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/a74ucu5jpl6hx4tx3lbs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C1QoPseK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/a74ucu5jpl6hx4tx3lbs.png" alt="CSS styles"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can set the size of the panes. First, we set the width and the height of the "scrollable-element". Of course, it needs to be smaller than the content, to display some scrollbars. Then, the width and the height of the "panes-wrapper" should be the sums of the widths and heights of containing panes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JiOmNU_---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/15kv0pb5ca3r3g85hnrv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JiOmNU_---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/15kv0pb5ca3r3g85hnrv.png" alt="Elements size helper table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have reached this step, your result might already be working as expected, but you have probably noticed that the bottom panes are covered by the top panes while scrolling. The same behavior also happens to the left and right panes. To avoid this overlay we need to add some margins to the panes, so that the bottom and top panes, and also the left and right panes push each other away.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h1VwfIZW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/53jzw1w9xgw7nf2zw2rk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h1VwfIZW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/53jzw1w9xgw7nf2zw2rk.png" alt="Elements margins helper table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the beginning of the article it was mentioned that if you want to be compatible with Mozilla Firefox browser you need to set z-index CSS style to some elements. The table below shows the required z-index values.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vp7s9lOc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/l5ayjs26shgm9hovugoz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vp7s9lOc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/l5ayjs26shgm9hovugoz.png" alt="z-index values"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary &amp;amp; example application
&lt;/h2&gt;

&lt;p&gt;If you set all properties as shown in this article, you will be able to achieve the expected result. We also prepared a quick example which allows you to look at the whole implementation. Feel free to use our experience and save time while trying to achieve a satisfactory outcome or try our &lt;a href="https://github.com/silevis/reactgrid"&gt;ReactGrid&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have fun :)&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/t0x86"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>react</category>
      <category>html</category>
      <category>css</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to integrate ReactGrid with Chart.js?</title>
      <dc:creator>Patryk Eliasz</dc:creator>
      <pubDate>Tue, 12 Jan 2021 08:51:18 +0000</pubDate>
      <link>https://dev.to/reactgrid/how-to-integrate-reactgrid-with-chart-js-3f75</link>
      <guid>https://dev.to/reactgrid/how-to-integrate-reactgrid-with-chart-js-3f75</guid>
      <description>&lt;p&gt;&lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=blogcharts" rel="noopener noreferrer"&gt;ReactGrid&lt;/a&gt; is a React.js component for displaying and editing data in a spreadsheet-like way. This guide shows you how to integrate it with the well-known pure Javascript library - &lt;a href="https://www.chartjs.org/" rel="noopener noreferrer"&gt;Chart.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F64i93s5pbjf05j7dgo9d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F64i93s5pbjf05j7dgo9d.png" alt="Audiogram app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why ReactGrid?
&lt;/h2&gt;

&lt;p&gt;There are plenty of different data tables available on the Internet, which perform great if you want to display one object per row. &lt;br&gt;
Each of these objects has to have exactly the same static properties, which are mapped to columns in the table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=blogcharts" rel="noopener noreferrer"&gt;ReactGrid&lt;/a&gt; was designed to be independent of your data model.&lt;br&gt;
It doesn't care about your schema. You can render anything in any cell and thus you are able to display things the way you like it.&lt;/p&gt;

&lt;p&gt;Unlike other grid components, &lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=blogcharts" rel="noopener noreferrer"&gt;ReactGrid&lt;/a&gt; also performs great on mobile devices or those with a touch capability and provides the same experience as on a desktop.&lt;/p&gt;

&lt;p&gt;Before we get started let's list three main tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;displaying the collected data will be achieved with &lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=blogcharts" rel="noopener noreferrer"&gt;ReactGrid&lt;/a&gt;. To be &lt;strong&gt;reactive&lt;/strong&gt; we will re-render the view only when the source data has changed.
In this example, raw data comes from an audiometer - a device that is used for making hearing tests.
In a nutshell, audiometer measures multiple hearing difficulties at many frequencies,  and the audiogram is a way of visualizing such disorders.&lt;/li&gt;
&lt;li&gt;visualize the collected data on the line chart using &lt;a href="https://www.chartjs.org/" rel="noopener noreferrer"&gt;Chart.js&lt;/a&gt; and its React wrapper,&lt;/li&gt;
&lt;li&gt;add a possibility to enter a new value and rerender the whole view with an updated state.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Let's code!
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Initialize the project&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nothing simpler - just type one of the commands below into your terminal to initiate a React app with Typescript support.&lt;br&gt;
'Create React App' will take care of all the necessary stuff.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Define useful interfaces and types&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, we need to declare a few interfaces and types that help us to keep everything in the right place and order.&lt;br&gt;
In this particular example, we know all about the data that we want to process.&lt;br&gt;
A good idea is to 'be as narrow' as possible.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Mark the columns and rows&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Relying on those interfaces now we can introduce &lt;code&gt;getColumns&lt;/code&gt; function. &lt;br&gt;
In our app, we got a &lt;code&gt;Line&lt;/code&gt; column, and after that, we got columns which are related to a particular frequency from 0Hz to 16000Hz.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The next stage is mapping all the rows. We make it in a similar way to previous examples.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Define the data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As we defined our data, it's time to define our data that we are working on. &lt;code&gt;getData&lt;/code&gt; function returns an object whose each key must exist within the &lt;code&gt;RowsMap&lt;/code&gt; interface. Each key of this object contains an array of &lt;code&gt;Freq&lt;/code&gt; objects.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Map the data to ReactGrid&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now we are ready to generate rows that directly feed into &lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=blogcharts" rel="noopener noreferrer"&gt;ReactGrid&lt;/a&gt;.  Each row contains the same amount of cells, but all of them can be arbitrarily placed in any order.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;The main component - &lt;code&gt;Audiogram&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is time to create the main component - &lt;code&gt;Audiogram&lt;/code&gt; and wrap up already written code. &lt;br&gt;
As you can see we stored our data inside React &lt;code&gt;useState&lt;/code&gt; hook. &lt;br&gt;
&lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=blogcharts" rel="noopener noreferrer"&gt;ReactGrid&lt;/a&gt; always expects two props - &lt;code&gt;columns&lt;/code&gt; (they are constant and don’t change over time) and &lt;code&gt;rows&lt;/code&gt; (they are calculated every time the &lt;code&gt;Audiogram&lt;/code&gt; component is rerendered).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;All that's left is to render the component with:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyge9zdk86yiams491hjr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyge9zdk86yiams491hjr.png" alt="ReactGrid displaying the data"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Apply changes with the cell editor
&lt;/h2&gt;

&lt;p&gt;There are two things left to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a header row to mark the data (devices and all the frequencies);&lt;/li&gt;
&lt;li&gt;Add possibility to edit data with &lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=blogcharts" rel="noopener noreferrer"&gt;ReactGrid&lt;/a&gt;'s cell editor;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Adding the header row&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To add it we have to create a short function called &lt;code&gt;getHeaderRow&lt;/code&gt;. As an argument, it gets a column order (as keys of columns) and returns a row object that contains only a cell of the &lt;code&gt;header&lt;/code&gt; type. We also added some green background to those cells.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkpn2rik57wk9ccej62j6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkpn2rik57wk9ccej62j6.png" alt="ReactGrid with a header row"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Editing frequency values in cell editor&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At this moment &lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=blogcharts" rel="noopener noreferrer"&gt;ReactGrid&lt;/a&gt; behaves as a read-only. To change that we updated the &lt;code&gt;Audiogram&lt;/code&gt; component by adding our handler function called &lt;code&gt;handleChanges&lt;/code&gt;. We expect that only &lt;code&gt;NumberCell&lt;/code&gt; will be changed, therefore we marked the &lt;code&gt;changes&lt;/code&gt; argument as &lt;code&gt;CellChange&amp;lt;NumberCell&amp;gt;[]&lt;/code&gt;. Our task is to change data on the basis &lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=blogcharts" rel="noopener noreferrer"&gt;ReactGrid&lt;/a&gt; has been rendered.&lt;/p&gt;

&lt;p&gt;Cell editor opens when it receives double-click action or the Enter key is pressed. &lt;br&gt;
Then you can type a new value in and then commit the change. If we &lt;code&gt;console.log(changes)&lt;/code&gt; we get an array of objects as shown below:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;To change our raw data we have to find &lt;code&gt;rowId&lt;/code&gt; where the change takes place. &lt;br&gt;
Then loop over all frequency samples and apply a new value (&lt;code&gt;change.newCell.value&lt;/code&gt;) to an appropriate cell or just return without changes.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Data visualization with Chart.js
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.chartjs.org/" rel="noopener noreferrer"&gt;Chart.js&lt;/a&gt; library delivers plenty of components to visualize data, but this time we focus on a single one - &lt;code&gt;Line&lt;/code&gt; from &lt;a href="https://github.com/reactchartjs/react-chartjs-2" rel="noopener noreferrer"&gt;&lt;code&gt;react-chartjs-2&lt;/code&gt;&lt;/a&gt; that we can use as a React component.&lt;/p&gt;

&lt;p&gt;We have to create two functions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;getChartData&lt;/code&gt; - this function should return an object that contains two fields. The &lt;code&gt;labels&lt;/code&gt; - which is an array of frequency title label and then &lt;code&gt;datasets&lt;/code&gt; field to provide the &lt;code&gt;data&lt;/code&gt; field which contains an array of values for each frequency. 
You can also style your line by setting for example a &lt;code&gt;backgroundColor&lt;/code&gt; or &lt;code&gt;pointRadius&lt;/code&gt; for a better experience.&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;getChartOptions&lt;/code&gt; - here we return an object that is compatible with &lt;code&gt;ChartOptions&lt;/code&gt; interface. 
We want to disable legend, set the title, display, and adjust axes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's all! The job is done, now you can check the result below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fl0f0raio6h7qdgq951et.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fl0f0raio6h7qdgq951et.png" alt="Complete app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/reactgrid-chartjs-audiogram-gtlgr?module=src/Audiogram.tsx"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;What you learned after completing this guide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what is &lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=blogcharts" rel="noopener noreferrer"&gt;ReactGrid&lt;/a&gt; and how to do a fully functional app; &lt;/li&gt;
&lt;li&gt;how you can use it in a reactive way;&lt;/li&gt;
&lt;li&gt;why Typescript is also helpful in a small-scale project to avoid the most common mistakes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you see integrating &lt;a href="https://reactgrid.com/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=blogcharts" rel="noopener noreferrer"&gt;ReactGrid&lt;/a&gt; with other libraries like &lt;a href="https://www.chartjs.org/" rel="noopener noreferrer"&gt;Chart.js&lt;/a&gt; is not so hard. Of course, you don't need to start a Typescript project and make all data mappings to compose a predictable solution.&lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>datatable</category>
    </item>
    <item>
      <title>What is ReactGrid and why is it unique?</title>
      <dc:creator>Patryk Eliasz</dc:creator>
      <pubDate>Mon, 11 Jan 2021 14:24:26 +0000</pubDate>
      <link>https://dev.to/reactgrid/what-is-reactgrid-and-why-is-it-unique-3l52</link>
      <guid>https://dev.to/reactgrid/what-is-reactgrid-and-why-is-it-unique-3l52</guid>
      <description>&lt;p&gt;ReactGrid is a React component which enables you to add spreadsheet-like behavior to your app. It was created to satisfy a narrow group of recipients for whom other products are not an appropriate solution.&lt;/p&gt;

&lt;p&gt;On the one hand there are data tables like Handsontable or ag-Grid. These render records row by row and offer various filtering, sorting and grouping methods. In 90% of the cases this functionality is fully sufficient.&lt;/p&gt;

&lt;p&gt;Then there are Spreadsheet web components like KendoUI Spreadsheet or dhtmlx Spreadsheet which display regular Excel sheets in the browser. They are able to interpret formulas and offer rich editing features for the end-user.&lt;/p&gt;

&lt;p&gt;ReactGrid places itself exactly in the middle between the two. It is not limited to a record-based model where each row has to have the same schema. The component enables you to create tables of any shape that look and feel like Excel-sheets. Additionally it integrates well with the data handling model provided by React.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F60p5s0km3jiikxh6nydr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F60p5s0km3jiikxh6nydr.png" alt="Adjust your grid view and behaviour to your needs with ReactGrid"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  When do you need ReactGrid in your app?
&lt;/h1&gt;

&lt;p&gt;ReactGrid was created to solve the issues in which we, web developers, weren’t satisfied with the existing spreadsheet or data grid solutions. You must have wanted to present your data in a rather unusual way more than once, for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create a field that aggregates values only from selected places;&lt;/li&gt;
&lt;li&gt;create an unusual combination of action and reaction;&lt;/li&gt;
&lt;li&gt;display unstructured data, e.g. MongoDB documents;&lt;/li&gt;
&lt;li&gt;sort or group data with an unusual structure together;&lt;/li&gt;
&lt;li&gt;react to data changes in a way that is fully controlled by you;&lt;/li&gt;
&lt;li&gt;transfer the solution implemented in the spreadsheet to a closed application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0u4dv9tczgcbkzmr1tbm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0u4dv9tczgcbkzmr1tbm.png" alt="Three ReactGrid fundamentals"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Reactivity with arbitrary cell placement
&lt;/h2&gt;

&lt;p&gt;To show the difference, we created a simple graph with two key aspects contained on the intersecting axes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;vertical — reactivity — a concept taken directly from React.js library. The opposite is imperative, you have full control over actions and their influence on the current view. In most cases you should follow the following pattern:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdtey6j514q9vniokcvge.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdtey6j514q9vniokcvge.png" alt="Reactivity in ReactGrid"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;horizontal — arbitrary cell placement — opportunity to “Thinking in rows and columns”, each row has the same schema. Our component allows you to place any cell anywhere. We have focused on a fully controlled cell schema defined by our cell template engine. Templating is a powerful feature that allows you to define cell behavior based on its current and future data state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7tj9czg5jaf1qh1qpoe9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7tj9czg5jaf1qh1qpoe9.png" alt="ReactGrid compared with another spreadsheet/datagrid components"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We want to be (and we are) more reactive and cell-oriented. Breaking with the approach known from such alternatives as agGrid, Handsontable, it is necessary to handle events through self-implemented callbacks. Implementing a basic cell change event relies on your implementation. We prepared examples where you can just copy and paste predefined implementation.&lt;/p&gt;

&lt;p&gt;ReactGrid’s content is rerendered only in case when visible data has changed or additional conditions such as a changed number of sticky rows and columns have appeared. Other examples might include handling scrolling (continuously following visible range for virtual scrolling), focusing cell, handling user actions like copying and pasting data. ReactGrid works perfectly even if you display a huge amount of cells — 10 000, 20 000, 100 000 is not a big deal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbtjjt3igxzwribx0bn6p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbtjjt3igxzwribx0bn6p.png" alt="Sample component lifecycle that uses ReactGrid"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s talk about a simplified lifecycle based on ReactGrid. The component containing ReactGrid (AppComponent) has its data (it is a Single Point Of Truth for ReactGrid), which contains data on the basis of which the grid view will be generated.&lt;/p&gt;

&lt;p&gt;The rendered view is ready to handle events coming from the user, e.g. changes committed in the cell editor. However, the component still behaves as read-only because a data update is required to change its contents. We can do this, for example, by implementing the onCellsChanged function (the example comes from the ReactGrid docs).&lt;/p&gt;

&lt;h2&gt;
  
  
  Touch devices friendly
&lt;/h2&gt;

&lt;p&gt;ReactGrid works perfectly with modern web browsers. The same goes for their mobile counterparts along with touchscreens. With ReactGrid, a mobile-friendly spreadsheet-like component, you can use your app in the same fashion and experience the same productivity as on a desktop device. Let’s have a look at the basic mobile usage case — cell selection, fill handle… it just works on ReactGrid.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdqwrpaihtrdcv5fywccc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdqwrpaihtrdcv5fywccc.gif" alt="ReactGrid compared with agGrid and Handsontable"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ReactGrid is NOT…
&lt;/h2&gt;

&lt;p&gt;You may wonder why our product “does not have” many popular functionalities, such as grouping, sorting, filtering? This is not really a disadvantage, but a feature! By getting them, you immediately agree to the restrictions imposed by the selected library. Here you manage how you sort your data and how the user can do it. Nothing prevents any cell from being, for example, a filter.&lt;/p&gt;

&lt;p&gt;What about formulas, toolbar, and coordinates? ReactGrid is a component in which we consciously implemented only the appearance and behavior known from typical spreadsheets, but without the implementation of the outer envelope. Our purpose was not to create the next Excel, but create whatever you like around it using component API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this short article, we showed three main principles which we developed ReactGrid with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reactivity — handle every event and process data in your way;&lt;/li&gt;
&lt;li&gt;arbitrary cell placement — forget about row schema and focus on cell,&lt;/li&gt;
&lt;li&gt;mobile-friendly — the same experience no matter what device you use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ReactGrid gives you the freedom to display and interact with your data to create a custom view with non-row-oriented data. We use it in our projects as a tool — not a complete solution. Therefore our experience shows that every solution resolved by ReactGrid is unique. We encouraging you to browse our website and Github repo.&lt;/p&gt;

</description>
      <category>react</category>
      <category>spreadsheet</category>
      <category>javascript</category>
      <category>datagrid</category>
    </item>
  </channel>
</rss>
