<?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: Petyo Ivanov</title>
    <description>The latest articles on DEV Community by Petyo Ivanov (@petyosi).</description>
    <link>https://dev.to/petyosi</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%2Fuser%2Fprofile_image%2F167357%2F1b7c2d42-e33c-4be2-b738-cf0283d7c0b1.jpeg</url>
      <title>DEV Community: Petyo Ivanov</title>
      <link>https://dev.to/petyosi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/petyosi"/>
    <language>en</language>
    <item>
      <title>Why I wrote my own state management for React Virtuoso</title>
      <dc:creator>Petyo Ivanov</dc:creator>
      <pubDate>Mon, 14 Dec 2020 17:05:57 +0000</pubDate>
      <link>https://dev.to/petyosi/why-i-wrote-my-own-state-management-for-react-virtuoso-1b54</link>
      <guid>https://dev.to/petyosi/why-i-wrote-my-own-state-management-for-react-virtuoso-1b54</guid>
      <description>&lt;p&gt;Almost 2 years after its first release, last Saturday I shipped &lt;code&gt;v1&lt;/code&gt; of &lt;a href="https://virtuoso.dev/"&gt;React Virtuoso&lt;/a&gt;. With this release, the state management framework powering Virtuoso is now available as a separate package called urx, &lt;br&gt;
with its own documentation and examples available at &lt;a href="https://urx.virtuoso.dev/"&gt;urx.virtuoso.dev&lt;/a&gt;. This is the story of what brought the development of the project there.&lt;/p&gt;
&lt;h2&gt;
  
  
  Virtuoso is not your Typical React App
&lt;/h2&gt;

&lt;p&gt;The popular React state management solutions are designed with the app in mind - a relatively large data tree with reducers rebuilding certain parts of it. Managing the state of the Virtuoso component is a different kind of problem. &lt;br&gt;
In its case, a multitude of &lt;strong&gt;continuously changing input values&lt;/strong&gt; from the DOM combine with the component properties into a relatively simple data structure - a list of items "windowed" to show the currently visible part of a large list. Here's a pseudo-code representation of what the state calculation looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// DOM input&lt;/span&gt;
&lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scrollTop&lt;/span&gt;
&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;viewportHeight&lt;/span&gt;
&lt;span class="nx"&gt;sizes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemSizes&lt;/span&gt;

&lt;span class="c1"&gt;// component properties&lt;/span&gt;
&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalCount&lt;/span&gt;
&lt;span class="nx"&gt;overscan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;overscan&lt;/span&gt;
&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;
&lt;span class="nx"&gt;groups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;groups&lt;/span&gt;

&lt;span class="c1"&gt;// ... intermediate calculations&lt;/span&gt;
&lt;span class="nx"&gt;sizeTree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rebuildSizeTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sizeTree&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sizes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;listRange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rebuildWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;overscan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;listDimensions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;listRange&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sizeTree&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;listDimensions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dimensions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// output of a list &lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;paddingTop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;paddingBottom&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dimensions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buildItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the catch - none of the dom/props above is a static value. They are &lt;strong&gt;streams of changing values&lt;/strong&gt; which should be efficiently propagated through the list/item calculation logic. The change propagation cannot be described efficiently with procedural code - you need a topology of dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initial Prototype - the Redux-based Failure
&lt;/h3&gt;

&lt;p&gt;My initial prototype of the component was Redux based. &lt;br&gt;
The good news was that the idea of using &lt;a href="https://github.com/petyosi/react-virtuoso/blob/master/src/AATree.ts"&gt;a binary tree structure&lt;/a&gt; for the item sizes worked. The bad news was that either I did not understand Redux or it was the incorrect tool for what I was doing. My code was a &lt;strong&gt;pile of interdependent reducers&lt;/strong&gt; that were repeatedly called with various combinations of values from actions and the existing state. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Da7nE7s_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://virtuoso.dev/img/blog/spaghetti.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Da7nE7s_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://virtuoso.dev/img/blog/spaghetti.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;An artistic interpretation of Virtuoso's Redux implementation. &lt;span&gt;Photo by &lt;a href="https://unsplash.com/@behy_studio?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Behnam Norouzi&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/spaghetti?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;.&lt;/small&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Second Attempt - Hooks
&lt;/h3&gt;

&lt;p&gt;Unsurprisingly, re-implementing the idea with hooks did not make it better. In fact, it looked like a step in the wrong direction, because the Redux implementation was at least easily unit-testable outside of React. I threw the spaghetti away and took a short break from the idea.&lt;/p&gt;
&lt;h3&gt;
  
  
  Third Pass - RxJS to the Rescue
&lt;/h3&gt;

&lt;p&gt;Staring at the code, I noticed the stream pattern. The scroll container was continuously "emitting" &lt;code&gt;scrollTop&lt;/code&gt; values. The viewport emitted its height when resizing. The list items emitted their sizes when rendering or when resizing. Squinting a little bit, even the values of the component properties looked like streams of changing values. Could those values be wrapped &lt;a href="https://www.learnrxjs.io/learn-rxjs/concepts/rxjs-primer#what-is-an-observable"&gt;into RxJS Observables&lt;/a&gt;? &lt;/p&gt;

&lt;p&gt;The next implementation of Virtuoso was a bag of &lt;strong&gt;input observables&lt;/strong&gt; that got combined and transformed to produce &lt;strong&gt;output observables&lt;/strong&gt;. The observables were put in a context, and wired up to "dumb" React components through &lt;code&gt;useInput(observable$)&lt;/code&gt; / &lt;code&gt;useOutput(observable$)&lt;/code&gt; &lt;br&gt;
pair of hooks that either pushed into the specified observable or re-rendered in response to a new value being emitted.&lt;/p&gt;

&lt;p&gt;This approach was an enormous improvement. Handing updates through the &lt;code&gt;combineLatest&lt;/code&gt; and &lt;code&gt;withLatestFrom&lt;/code&gt; operators eliminated the duplication from the Redux actions. The observable combinatory logic was easily testable outside of React. Finally, rather than dealing with a state tree, I subscribe to the output observables I needed in the specific component, optimizing its rendering. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_gxWFkW6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://virtuoso.dev/img/blog/pipes.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_gxWFkW6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://virtuoso.dev/img/blog/pipes.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Observables felt like a well organized, permanent piping and transformation system of the component state. &lt;span&gt;Photo by &lt;a href="https://unsplash.com/@hooverpaul55?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Paul Teysen&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/complex-pipes?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;.&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Building Virtuoso was fun again. The version which I mustered the courage to announce to the world was built on top of RxJS - and it got a fairly positive response in &lt;a href="https://www.reddit.com/r/reactjs/comments/bp7ub6/react_virtuoso_a_virtual_scrolling_library_with/"&gt;/r/reactjs&lt;/a&gt;. &lt;br&gt;
A few redditors noticed the RxJS dependency, but nobody called me out on the state management blasphemy I have created. Instead, they complained about the bundle size. RxJS was too large for a small UI component. And they were right.&lt;/p&gt;

&lt;p&gt;This problem was not unsolvable, because I used a very small part of RxJS. Over the weekend, I whipped a home-grown implementation of what I was using from RxJS and threw it in a cheekily named &lt;code&gt;tinyrx.ts&lt;/code&gt;. The RxJS dependency was gone and the package was down to 7kB according to Bundlephobia. In hindsight, doing that replacement back then was the right choice. Doing that at a later stage would not be that easy.&lt;/p&gt;
&lt;h2&gt;
  
  
  Fast Forward One Year - Virtuoso is Used for Chats and Feeds
&lt;/h2&gt;

&lt;p&gt;The problem solved by Virtuoso (easy virtualization of variably sized items) was hard enough for the project to attract and retain supportive (and smart!) early adopters - who endured my poor understanding of React &lt;br&gt;
and educated me on the finer arts of improving React performance (shoutout to &lt;a href="https://github.com/FezVrasta"&gt;Federico Zivolo a.k.a. FezVrasta&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;I also understood a lot more about my users and their virtual lists. Many of them were building &lt;strong&gt;chats and data feeds&lt;/strong&gt; - a use case which can be best described as a &lt;strong&gt;reverse endless scrolling&lt;/strong&gt;. Reverse scrolling was a problem that I originally did not intend to address. And the business as usual new features overburdened my naive &lt;code&gt;VirtuosoStore&lt;/code&gt; implementation, a single JS function that initiated and combined the entire set of observables used in the component. The project needed a rewrite to move forward.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Pitd0ivU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://virtuoso.dev/img/blog/subjects-are-signals.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Pitd0ivU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://virtuoso.dev/img/blog/subjects-are-signals.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;My fellow developers had more than enough of me explaining why observables made sense in React.&lt;/small&gt;&lt;/p&gt; 
&lt;h2&gt;
  
  
  urx was Born
&lt;/h2&gt;

&lt;p&gt;As these things go, I fell in love with my pet reactive state management pattern, so I decided to give it its own name and proper documentation. It also grew up a bit and got some original looks. Rather than just being a poor man's RxJS, the urx library includes the &lt;a href="https://urx.virtuoso.dev/docs/api/modules/_urx_src_system_"&gt;systems abstraction&lt;/a&gt; as a way to organize Observables into testable components. &lt;br&gt;
Subjects and Behavior Subjects (the names of which I find highly confusing) are renamed &lt;a href="https://urx.virtuoso.dev/docs/api/modules/_urx_src_streams_"&gt;to streams and stateful streams&lt;/a&gt;. &lt;br&gt;
The React abstraction got its own package, dedicated to the magical transformation of an &lt;a href="https://urx.virtuoso.dev/docs/api/modules/_react_urx_src_index_"&gt;urx system into a React component&lt;/a&gt;. &lt;/p&gt;
&lt;h2&gt;
  
  
  The Result
&lt;/h2&gt;

&lt;p&gt;React Virtuoso consists of 1550 lines of code in framework-agnostic urx systems, wrapped up in &lt;a href="https://github.com/petyosi/react-virtuoso/blob/master/src/List.tsx"&gt;~200 lines of dumb react components&lt;/a&gt; wired up to the "master" List system. The react code is downright boring - the only unit tests against it are mostly checking the server-side-rendering specifics. The &lt;a href="https://github.com/petyosi/react-virtuoso/tree/master/test"&gt;rest of the test suite&lt;/a&gt; is written against the various urx systems. As an example, here's how the &lt;code&gt;domIOSystem&lt;/code&gt; looks:&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;connect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;scan&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;system&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;statefulStream&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="s1"&gt;@virtuoso.dev/urx&lt;/span&gt;&lt;span class="dl"&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;UP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;up&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&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;DOWN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;down&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ScrollDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;UP&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;DOWN&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;domIOSystem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;system&lt;/span&gt;&lt;span class="p"&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="nx"&gt;scrollTop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&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="nx"&gt;deviation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;statefulStream&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;smoothScrollTargetReached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kc"&gt;true&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="nx"&gt;statefulScrollTop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;statefulStream&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;viewportHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&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="nx"&gt;scrollTo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ScrollToOptions&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="nx"&gt;scrollBy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ScrollToOptions&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;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scrollTop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;statefulScrollTop&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;scrollDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;statefulStream&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ScrollDirection&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;DOWN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;scrollTop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;scrollTop&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;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;scrollTop&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prevScrollTop&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;UP&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DOWN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;prevScrollTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;scrollTop&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;direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DOWN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;prevScrollTop&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="k"&gt;as&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ScrollDirection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;prevScrollTop&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;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;direction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;scrollDirection&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="c1"&gt;// input&lt;/span&gt;
      &lt;span class="nx"&gt;scrollTop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;viewportHeight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;smoothScrollTargetReached&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

      &lt;span class="c1"&gt;// signals&lt;/span&gt;
      &lt;span class="nx"&gt;scrollTo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;scrollBy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

      &lt;span class="c1"&gt;// state&lt;/span&gt;
      &lt;span class="nx"&gt;scrollDirection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;statefulScrollTop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;deviation&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;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;singleton&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="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The component implementation is quite portable; when React goes out of fashion, the underlying stream system can be wrapped in a different UI framework. &lt;/p&gt;

&lt;h2&gt;
  
  
  It's not all Roses, but it's Worth it
&lt;/h2&gt;

&lt;p&gt;Reactive programming is not a silver bullet, nor magic fairly land where your code has no bugs. At some point, the &lt;a href="https://en.wikipedia.org/wiki/Reactive_programming#Implementation_challenges_in_reactive_programming"&gt;Reactive Programming Wikipedia Article Implementation Challenges&lt;/a&gt; &lt;br&gt;
became a checklist of the errors and the subtle issues I encountered. React, while perceptive to the approach, is also not explicitly designed to work with observable streams. &lt;/p&gt;

&lt;p&gt;Still, I am certain that I could not implement React Virtuoso with any other state management. &lt;/p&gt;

&lt;h2&gt;
  
  
  Should you try urx?
&lt;/h2&gt;

&lt;p&gt;The short answer is probably "no" unless you are implementing something similar to React Virtuoso. The popular state management tools have enormous healthy ecosystems, documentation, and tooling built for them. &lt;/p&gt;

&lt;p&gt;However, you can go &lt;a href="https://urx.virtuoso.dev/"&gt;through the documentation&lt;/a&gt; even for the fun of it - it is a different take on UI state management. If you want to see a real-world example of how systems are built and organized, you can dig into &lt;a href="https://github.com/petyosi/react-virtuoso/tree/master/src"&gt;the source code of React Virtuoso itself&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Reactive Programming for React Developers Part 2 - Integrate with React</title>
      <dc:creator>Petyo Ivanov</dc:creator>
      <pubDate>Mon, 03 Jun 2019 05:56:12 +0000</pubDate>
      <link>https://dev.to/petyosi/reactive-programming-for-react-developers-part-2-integrate-with-react-5883</link>
      <guid>https://dev.to/petyosi/reactive-programming-for-react-developers-part-2-integrate-with-react-5883</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/petyosi/reactive-programming-for-react-developers-the-absolute-beginner-guide-5eeg"&gt;first part of the series&lt;/a&gt;, we went through some basics of reactive programming. Today, we are going to implement a small (but interesting enough) task using React as the view and a &lt;strong&gt;reactive engine&lt;/strong&gt; as the backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  First Take: Counter
&lt;/h2&gt;

&lt;p&gt;As a warm-up, we are going to do something similar to the &lt;a href="https://redux.js.org/introduction/examples"&gt;Redux Counter example&lt;/a&gt; - a button which clicks and increments a value. Let's create a function which creates an input stream for the button click and an output stream for the counter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;subscribe&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;callbag-subscribe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;subject&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;callbag-subject&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;pipe&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;callbag-pipe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;scan&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;callbag-scan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;startWith&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;callbag-start-with&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;createEngine&lt;/span&gt;&lt;span class="p"&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;increments$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;subject&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;counter$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
    &lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;increments$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;acc&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;startWith&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="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="nx"&gt;counter$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;increments$&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;There we go. If you went through the first part of the series, the above should not look that scary. We use the &lt;code&gt;scan&lt;/code&gt; operator to capture and accumulate the clicks counter. We specify the initial value of the counter using &lt;code&gt;startWith&lt;/code&gt;. Let's connect it to React:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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;render&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="s1"&gt;react-dom&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;useCallbagInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useCallbagOutput&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="s1"&gt;./CallbagHooks&lt;/span&gt;&lt;span class="dl"&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;createEngine&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="s1"&gt;./engine&lt;/span&gt;&lt;span class="dl"&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;engine&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;createEngine&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;buttonClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useCallbagInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;increments$&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;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useCallbagOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;counter$&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;buttonClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Click me&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Button was clicked &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; times&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We put the streams in the state of the component (leaving it read-only), and connect them to React using the &lt;code&gt;useCallbagInput / useCallbagOutput&lt;/code&gt; hooks, respectively. Let's see it in action!&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/react-m8retc?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Notice: you can examine the hooks implementation in the example above - it is the glue between the streams and React's state. The &lt;code&gt;useCallbagInput&lt;/code&gt; is not even a real hook. &lt;/p&gt;

&lt;p&gt;The above approach looks like an overcomplication - you can achieve the same with &lt;code&gt;useState&lt;/code&gt; or &lt;code&gt;useReducer&lt;/code&gt; in fewer, simpler lines of code. However, it accomplished something important - it encapsulated the logic of our app in a building block which resides outside of our React components. You can easily write tests against it, without any React component/rendering involved.&lt;/p&gt;

&lt;p&gt;Next, let's try something more complex!&lt;/p&gt;

&lt;h2&gt;
  
  
  Second step: Calculator
&lt;/h2&gt;

&lt;p&gt;We will build a calculator which sums two or more numbers and keeps track of the previous sums. Check the following prototype for a better idea:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/react-jz4jwh?embed=1&amp;amp;view=preview&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Let's see what are the requirements for our engine:&lt;/p&gt;

&lt;p&gt;We need: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;something to process the clicks of the number buttons&lt;/li&gt;
&lt;li&gt;something to process the click of the 'sum' button&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;something to update the numbers to be summed&lt;/li&gt;
&lt;li&gt;something to update the calculations so far&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From the engine's point of view, these are two input streams and two output streams. The input streams push data into the store (numbers, sum); the output streams output the results to the consumer (in our case, the React UI). Thinking in Redux terms (although not exact mapping), the input streams are the actions, while the output streams are the state. Don't get hung up on this parallel though. &lt;/p&gt;

&lt;h3&gt;
  
  
  Build the Engine
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;subject&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;callbag-subject&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;pipe&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;callbag-pipe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;map&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;callbag-map&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;scan&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;callbag-scan&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;buffer&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;callbag-buffer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cut&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;callbag-cut&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numbersToSumString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;+&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;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&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;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&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;createEngine&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="nx"&gt;numbersToSum$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;subject&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;calculate$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;subject&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;solutions$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;numbersToSum$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;calculate$&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;numbers&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;numbersToSumString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;solutionsSoFar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;solution&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;solution&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;solutionsSoFar&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pendingNumbers$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;numbersToSum$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;cut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;calculate$&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;numbersToSumString&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="c1"&gt;// input&lt;/span&gt;
    &lt;span class="nx"&gt;numbersToSum$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;calculate$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="c1"&gt;// output&lt;/span&gt;
    &lt;span class="nx"&gt;solutions$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;pendingNumbers$&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;We finally got to the fun parts! We combine the two input streams (&lt;code&gt;numbersToSum$&lt;/code&gt; and &lt;code&gt;calculate$&lt;/code&gt;) in different ways in order to build our output streams - the calculated solutions and the numbers in the current unfinished solution. &lt;/p&gt;

&lt;p&gt;The part which I appreciate the most about the implementation is that the engine is stateful, but we don't deal with that manually. Instead, we use the &lt;code&gt;scan&lt;/code&gt;, &lt;code&gt;buffer&lt;/code&gt; and &lt;code&gt;cut&lt;/code&gt; operators to the job for us.&lt;/p&gt;

&lt;p&gt;The next example connects the engine to the React view we started with:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/react-q6xkkv?embed=1&amp;amp;view=editor&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In addition to the hooks from the Counter example, we put the engine in a context and then access the streams we need in the child components. Notice that, unlike Redux, the streams do not change over time. Instead, they act like &lt;strong&gt;permanent pipes&lt;/strong&gt; which take care of accepting inputs from events in the various parts of the app and delivering the updated values where necessary. &lt;/p&gt;

&lt;h2&gt;
  
  
  Why Callbag and not RxJS?
&lt;/h2&gt;

&lt;p&gt;The engine implementation would look mostly the same if we used RxJS. For the purposes of the tutorial, callbag felt simpler (everything is a function!).&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should I care about that? React already has hooks, Redux, MobX, etc.?
&lt;/h2&gt;

&lt;p&gt;Indeed - however, consider this more of a thought-provoking exercise on how we can program &lt;strong&gt;outside&lt;/strong&gt; of the framework. Compared to the traditional imperative approach, coding your logic with streams feels like programming on a higher level. Notice how the implementation above has zero &lt;code&gt;if&lt;/code&gt; statements, no variable reassignments, and no loops. Instead, we have a few pure functions composed with pre-made operators.&lt;/p&gt;

&lt;h2&gt;
  
  
  I want to learn more!
&lt;/h2&gt;

&lt;p&gt;An excellent resource to get you excited is &lt;a href="https://rxmarbles.com/"&gt;RxMarbles&lt;/a&gt; - without any actual code, it shows the power of the Rx observables. Most, if not all of the Rx operators have their counterparts implemented &lt;a href="https://github.com/callbag/callbag/wiki"&gt;in Callbag&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Reactive Programming for React Developers - the Absolute Beginner Guide</title>
      <dc:creator>Petyo Ivanov</dc:creator>
      <pubDate>Fri, 31 May 2019 07:42:15 +0000</pubDate>
      <link>https://dev.to/petyosi/reactive-programming-for-react-developers-the-absolute-beginner-guide-5eeg</link>
      <guid>https://dev.to/petyosi/reactive-programming-for-react-developers-the-absolute-beginner-guide-5eeg</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;In the &lt;a href="https://virtuoso.dev" rel="noopener noreferrer"&gt;my recent adventure&lt;/a&gt;, I decided to find the one true way to manage the internal state of a complex React component. A virtualized list is a complex affair. Users scroll and load new data, items resize because images load, devices change orientation. Sometimes, all of the above happens simultaneously.   &lt;/p&gt;

&lt;p&gt;I started with a redux-like store. A couple of days later, I ended up in entangled nested reducers and a bunch of repetition I could not get rid of. The available tests could not help me figure out why the component was behaving in unexpected ways. &lt;/p&gt;

&lt;p&gt;I was here, quite fast:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feer4fg72flti89tpakyx.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feer4fg72flti89tpakyx.jpeg" width="780" height="593"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  artist: &lt;a href="http://ma.nu/graphics/" rel="noopener noreferrer"&gt;Manu Cornet&lt;/a&gt;
&lt;/h6&gt;

&lt;p&gt;There must be a better way. Or so, I thought.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's Try Reactive Programming! Enter RxJS
&lt;/h2&gt;

&lt;p&gt;Figuring out RxJS while learning reactive programming was hard. RxJS is extremely powerful at the cost of being complex. A bunch of abstractions which did not immediately click or were named in the exact opposite way from how I understood them - hot and cold Observables, Observers, Subscribers, Subscriptions, and Schedulers, oh my.  Nevertheless, I managed to plow through. Thanks to &lt;a href="https://www.learnrxjs.io/" rel="noopener noreferrer"&gt;Learn RxJS&lt;/a&gt; and &lt;a href="https://rxmarbles.com/" rel="noopener noreferrer"&gt;RxMarbles&lt;/a&gt;, the component store was re-done. (Don't dive into the resources above, remember them for later. They are long and awesome and get hard really fast. Finish this article first). &lt;/p&gt;

&lt;p&gt;The result implementation was beautiful, 1/4 the size of the redux store, testable and reliable. Beauty is in the eye of the beholder of course. The first version of Virtuoso shipped with RxJS store implementation. &lt;/p&gt;

&lt;p&gt;Looks awesome, they said. Not gonna use it, RxJS is huge, no way I am adding this as a dependency, they said. Sigh. &lt;/p&gt;

&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/Dunning%E2%80%93Kruger_effect" rel="noopener noreferrer"&gt;Dunning-Kruger effect&lt;/a&gt; kicked in. I knew enough about reactive programming to replace RxJS with a small home-grown implementation. Better do this early, before I add more complex features. &lt;/p&gt;

&lt;p&gt;It worked, bringing the usual amount of hard to trace bugs. &lt;/p&gt;

&lt;p&gt;You are reinventing the wheel, they said. Check &lt;a href="https://github.com/callbag/callbag" rel="noopener noreferrer"&gt;Callbag&lt;/a&gt;, they said. I should have asked earlier. Anyway, the home-grown solution was there, and it worked. Better is the enemy of good enough. Stop messing around and finish what you have started. Let me browse the &lt;a href="https://gist.github.com/staltz/868e7e9bc2a7b8c1f754" rel="noopener noreferrer"&gt;Callbag docs&lt;/a&gt; really quick...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;So let's cut the bullshit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reactive programming is programming with asynchronous data streams&lt;/strong&gt;.&lt;br&gt;
In a way, this isn't anything new. Event buses or your typical click events are really an asynchronous event stream, on which you can observe and do some side effects. Reactive is that idea on steroids. You are able to create data streams of anything, not just from click and hover events. Streams are cheap and ubiquitous, anything can be a stream: variables, user inputs, properties, caches, data structures, etc. For example, imagine your Twitter feed would be a data stream in the same fashion that click events are. You can listen to that stream and react accordingly.&lt;/p&gt;

&lt;p&gt;On top of that, you are given an amazing toolbox of functions to combine, create and filter any of those streams. That's where the "functional" magic kicks in. A stream can be used as an input to another one. Even multiple streams can be used as inputs to another stream. You can merge two streams. You can filter a stream to get another one that has only those events you are interested in. You can map data values from one stream to another new one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There we go. That's the starting point I think everyone needs. This is what inspired me to write this post. &lt;/p&gt;

&lt;p&gt;What follows is what I consider the &lt;strong&gt;bare minimum&lt;/strong&gt; of what you need to understand about reactive programming, &lt;strong&gt;presented as jest tests&lt;/strong&gt;. I will stick to things which can be useful in React projects, where binding to a DOM element events directly does not make much sense. This is &lt;a href="https://codesandbox.io/s/modest-gauss-huyw7" rel="noopener noreferrer"&gt;the full test suite&lt;/a&gt; - let's go through each test. We are using Callbag as the underlying implementation. However, all of the above would look mostly the same with RxJS. Don't worry if you don't know Jest. The assertions should be self-explanatory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Subject, Subscriber and Observe
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subject emits values to its subscribers&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="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="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;subject&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;subscriber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subscriber&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Ignore the "1" parameter for now&lt;/span&gt;
  &lt;span class="nf"&gt;a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;foo&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pretty much captures the whole idea of reactive programming. In the above, we: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create a stream &lt;code&gt;a&lt;/code&gt;, which in our case is a generic subject;&lt;/li&gt;
&lt;li&gt;create a subscriber, which acts on the values coming from the stream(in this case, we verify that we received the correct value);&lt;/li&gt;
&lt;li&gt;we attach the subscriber to the stream using &lt;code&gt;observe&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;we push &lt;code&gt;"foo"&lt;/code&gt; in the stream &lt;code&gt;a&lt;/code&gt;;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the above makes sense to you, congratulations! The rest of the examples just add small blocks on top of that. &lt;/p&gt;

&lt;h2&gt;
  
  
  Behavior Subject
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;behavior subject emits previously pushed values to new subscribers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;done&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="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;behaviorSubject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bar&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;subscriber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;done&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subscriber&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;a&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;Next, we have the behavior subject. Its behavior is very similar to the vanilla subject, with one exception - the behavior subject &lt;strong&gt;is stateful&lt;/strong&gt;. This means that attached subscribers will immediately be called with the last value of the subject. Also, it is constructed with an initial value. In a nutshell, subscribing to such subject means that you will be called immediately. &lt;/p&gt;

&lt;p&gt;Behavior subjects are prevalent in the Virtuoso store implementation - that's where it keeps most of its state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pipe and Map
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pipe and map transform the incoming stream values&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;done&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="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;subject&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;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;done&lt;/span&gt;&lt;span class="p"&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;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Passing values around is not much fun. Thanks to &lt;code&gt;pipe&lt;/code&gt; and &lt;code&gt;map&lt;/code&gt;, we create an &lt;strong&gt;output stream&lt;/strong&gt; (&lt;code&gt;b&lt;/code&gt;) which transforms and emits values coming from &lt;code&gt;a&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Combine
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;combine takes values from two streams&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;done&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="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;subject&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;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;subject&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;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vals&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vals&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nf"&gt;done&lt;/span&gt;&lt;span class="p"&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;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

  &lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nf"&gt;a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;b&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pipe, combine and map work together&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;done&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="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;subject&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;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;subject&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;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;done&lt;/span&gt;&lt;span class="p"&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;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
  &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;aVal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bVal&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;aVal&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;bVal&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nf"&gt;a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;b&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&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;code&gt;combine&lt;/code&gt; is what I consider the last essential tool we need. It allows you to build an output stream which transforms incoming values from two or more input streams.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus - &lt;code&gt;scan&lt;/code&gt; and &lt;code&gt;sampleCombine&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://codesandbox.io/s/modest-gauss-huyw7" rel="noopener noreferrer"&gt;test suite&lt;/a&gt; includes two more tests that show how &lt;code&gt;scan&lt;/code&gt; and &lt;code&gt;sampleCombine&lt;/code&gt; work. If the examples so far make sense to you, you should have little trouble figuring them out. &lt;/p&gt;

&lt;p&gt;Stay tuned for the next post, where we are going to build a simple store from subjects and integrate it with a React component. We will also talk about why the heck would one need to do that when you can use hooks, Redux, etc.&lt;/p&gt;

&lt;p&gt;In the meantime, go through &lt;a href="https://gist.github.com/staltz/868e7e9bc2a7b8c1f754" rel="noopener noreferrer"&gt;The introduction to Reactive Programming you've been missing&lt;/a&gt; from &lt;a href="https://twitter.com/andrestaltz" rel="noopener noreferrer"&gt;André Staltz&lt;/a&gt;. You can also fork the sandbox and add more tests for the some of &lt;a href="https://github.com/callbag/callbag/wiki" rel="noopener noreferrer"&gt;callbag utilities listed in the Callbag Wiki&lt;/a&gt;. Share your forks in the comments!&lt;/p&gt;

</description>
      <category>react</category>
      <category>reactive</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Creating Beautiful Virtualized Lists with Material-UI and React Virtuoso</title>
      <dc:creator>Petyo Ivanov</dc:creator>
      <pubDate>Tue, 28 May 2019 16:38:16 +0000</pubDate>
      <link>https://dev.to/petyosi/creating-beautiful-virtualized-lists-with-material-ui-and-react-virtuoso-31i3</link>
      <guid>https://dev.to/petyosi/creating-beautiful-virtualized-lists-with-material-ui-and-react-virtuoso-31i3</guid>
      <description>&lt;p&gt;If you did not get the news, &lt;a href="https://material-ui.com/blog/material-ui-v4-is-out/"&gt;Material-UI v4 is out&lt;/a&gt;. Awesome announcement indeed; the Material Design system is amazing. And a mature, popular, open-source react library that implements the material design specs? We live in great times. &lt;/p&gt;

&lt;p&gt;My goal with the &lt;a href="https://virtuoso.dev"&gt;React Virtuoso&lt;/a&gt; library is to provide "chromeless" engine components which complement and power-up exiting UI libraries with advanced virtualization behavior. Version 0.6 allows you to replace the component structure with components of your choice. Today, we will use the Material-UI list components as containers in React Virtuoso to build a Material-looking virtualized list.&lt;/p&gt;

&lt;p&gt;The final result looks like this:&lt;br&gt;
&lt;iframe src="https://stackblitz.com/edit/github-hv734y?embed=1&amp;amp;view=preview&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Ready? Go!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Hello World
&lt;/h2&gt;

&lt;p&gt;A relatively modest step - we power up a new Stackblitz react project, and add the starter Virtuoso example - a list with 500 &lt;code&gt;Item {index}&lt;/code&gt; items. the Virutoso component configuration is easy; you pass some dimensions (you can pass anything, including &lt;code&gt;%&lt;/code&gt;, &lt;code&gt;rem&lt;/code&gt;, etc), the total of items to render, and the &lt;code&gt;item&lt;/code&gt; render prop. The component figures out the rest for you.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/github-hh6j8f?embed=1&amp;amp;view=editor&amp;amp;file=src/index.js" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Add material UI
&lt;/h2&gt;

&lt;p&gt;Let's make that list stylish! By default, Virtuoso renders its list container as a &lt;code&gt;div&lt;/code&gt;, and each individual item in a &lt;code&gt;div&lt;/code&gt; wrapper. We swap those for their Material-UI counterparts by specifying the &lt;code&gt;ListContainer&lt;/code&gt; and &lt;code&gt;ItemContainer&lt;/code&gt; properties. They render &lt;code&gt;ul&lt;/code&gt; and &lt;code&gt;li&lt;/code&gt; under the hood - works for us! &lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/github-ybd8u6?embed=1&amp;amp;view=editor&amp;amp;file=src/index.js" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Add real (fake) data
&lt;/h2&gt;

&lt;p&gt;Displaying &lt;code&gt;Item 40&lt;/code&gt; is quite boring, and, most likely, not what you need in your project. Let's show real data. Or at least, something that looks more convincing. In the next step, we generate a set of 500 user records using the &lt;a href="https://www.npmjs.com/package/faker"&gt;awesome faker library&lt;/a&gt; and display them in the list. We also make the list structure more complex by adding an avatar to each item. To keep up with the trends, we separate the data from the presentation by putting the user record generation in a reusable hook.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/github-4pvb43?embed=1&amp;amp;view=editor&amp;amp;file=src/data.js" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Final step - endless scrolling
&lt;/h2&gt;

&lt;p&gt;This is the most interesting part of the exercise. Loading 500 records in a single step is not a good idea. Instead, we start the list with 50 records, and add more when the user scrolls down. The hook we did in the previous step comes in handy; we extend it further to expose a &lt;code&gt;loadMore&lt;/code&gt; method which simulates a roundtrip to the server and appends more records to the existing array. The &lt;code&gt;loadMore&lt;/code&gt; call is wired up to Virtuoso's &lt;code&gt;endReached&lt;/code&gt; callback property.&lt;/p&gt;

&lt;p&gt;We also introduce two other minor enhancements: a footer which displays &lt;code&gt;loading...&lt;/code&gt; in case the user scrolls too fast, and an &lt;code&gt;overscan&lt;/code&gt; property which controls the eagerness of the load more behavior. &lt;br&gt;
&lt;iframe src="https://stackblitz.com/edit/github-hv734y?embed=1&amp;amp;view=editor&amp;amp;file=src/index.js" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;And, we are done! Was it shorter and simpler than expected? Are you looking for more? If so, go and check &lt;a href="https://virtuoso.dev/material-ui-endless-scrolling/"&gt;the advanced example&lt;/a&gt; in the docs - In addition to the above, it shows grouping with sticky items, optimizing the scrolling experience by hiding the avatars during scrolling. &lt;/p&gt;

</description>
      <category>react</category>
      <category>material</category>
      <category>javascript</category>
    </item>
    <item>
      <title>React Virtuoso - an elegant virtual list component
</title>
      <dc:creator>Petyo Ivanov</dc:creator>
      <pubDate>Tue, 14 May 2019 09:08:32 +0000</pubDate>
      <link>https://dev.to/petyosi/react-virtuoso-an-elegant-virtual-list-component-2ni9</link>
      <guid>https://dev.to/petyosi/react-virtuoso-an-elegant-virtual-list-component-2ni9</guid>
      <description>&lt;p&gt;Hey everyone, &lt;/p&gt;

&lt;p&gt;after some struggle with large data sets, i decided to scratch my own itch and build a proper component that can display variable height items without much hassle - &lt;a href="https://github.com/petyosi/react-virtuoso"&gt;React Virtuoso&lt;/a&gt;. Please let me know what you think about the implementation and the feature set. &lt;/p&gt;

&lt;p&gt;a few interesting details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;the component is written in typescript, and uses the &lt;a href="https://github.com/palmerhq/tsdx"&gt;tsdx scaffold&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the internal state is &lt;a href="https://github.com/petyosi/react-virtuoso/blob/master/src/virtuosostore.tsx"&gt;implemented with rxjs&lt;/a&gt;. propagating the observables changes works quite well with the hooks api. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
    </item>
  </channel>
</rss>
