<?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: Vikas Kumar</title>
    <description>The latest articles on DEV Community by Vikas Kumar (@vikas).</description>
    <link>https://dev.to/vikas</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%2F40636%2Fba9cf7aa-c913-4bf0-a0ff-766928ff40ae.JPG</url>
      <title>DEV Community: Vikas Kumar</title>
      <link>https://dev.to/vikas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vikas"/>
    <language>en</language>
    <item>
      <title>Unlocking Performance with AsyncJob: Specific Use Cases for I/O-Bound Operations</title>
      <dc:creator>Vikas Kumar</dc:creator>
      <pubDate>Tue, 05 Aug 2025 08:44:58 +0000</pubDate>
      <link>https://dev.to/vikas/unlocking-performance-with-asyncjob-specific-use-cases-for-io-bound-operations-368e</link>
      <guid>https://dev.to/vikas/unlocking-performance-with-asyncjob-specific-use-cases-for-io-bound-operations-368e</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7iy3dfi0599hpcsiaid9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7iy3dfi0599hpcsiaid9.png" alt="Rails async" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Elasticsearch Scaling Nightmare
&lt;/h2&gt;

&lt;p&gt;Picture this: Your Rails application is humming along nicely until suddenly, user growth explodes. Great news, right? Not for our job queue.&lt;/p&gt;

&lt;p&gt;In a previous application I worked on, we faced significant challenges scaling ActiveJobs, primarily due to numerous Elasticsearch indexing and other I/O-bound tasks. As our user base grew, thousands of small jobs overwhelmed our queue, creating a perfect storm of bottlenecks despite our best efforts at dynamic worker scaling.&lt;/p&gt;

&lt;p&gt;We tried all the usual solutions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Increased worker counts (which quickly hit diminishing returns)&lt;/li&gt;
&lt;li&gt;Added more powerful servers (hello, spiraling AWS bills)&lt;/li&gt;
&lt;li&gt;Optimized database connections (still not enough)&lt;/li&gt;
&lt;li&gt;Tweaked job priorities and batching strategies (marginal improvements at best)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yet we still hit hard limits with database connections, memory consumption, and infrastructure costs. The fundamental issue wasn’t our implementation,it was the thread-based job processing paradigm itself, which simply wasn’t optimized for our I/O-heavy workload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why AsyncJob for I/O-Bound Operations?
&lt;/h2&gt;

&lt;p&gt;Enter &lt;a href="https://github.com/socketry/async-job" rel="noopener noreferrer"&gt;AsyncJob&lt;/a&gt;, a gem that fundamentally reimagines how Ruby handles concurrent operations by leveraging &lt;strong&gt;Ruby fibers&lt;/strong&gt; for cooperative multitasking.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Thread vs. Fiber Difference
&lt;/h3&gt;

&lt;p&gt;To understand why this matters, let’s break down what happens during an Elasticsearch indexing operation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With traditional thread-based job processors (like SolidQueue):&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A thread makes an HTTP request to Elasticsearch&lt;/li&gt;
&lt;li&gt;The thread blocks while waiting for a response&lt;/li&gt;
&lt;li&gt;The OS must context-switch to another thread&lt;/li&gt;
&lt;li&gt;Each thread requires its own memory stack (often 1MB+ per thread)&lt;/li&gt;
&lt;li&gt;Thread context switching has significant overhead&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;With fiber-based AsyncJob:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A fiber makes an HTTP request to Elasticsearch&lt;/li&gt;
&lt;li&gt;The fiber voluntarily yields control while waiting&lt;/li&gt;
&lt;li&gt;Another fiber can immediately use the same thread&lt;/li&gt;
&lt;li&gt;Fibers are lightweight (a few KB each)&lt;/li&gt;
&lt;li&gt;Switching between fibers is extremely efficient&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach is exceptionally efficient for operations that spend most of their time waiting for external resources (I/O-bound), because instead of wasting CPU cycles waiting for responses, the system can process other jobs in the meantime.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started with AsyncJob
&lt;/h2&gt;

&lt;p&gt;Integrating AsyncJob into your Rails application is surprisingly straightforward. The gem provides an adapter for ActiveJob, allowing you to selectively apply it to jobs that would benefit most from fiber-based processing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;Add these gems to your Gemfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gem 'async-job'
gem 'async-job-adapter-active_job'
gem 'async-job-processor-redis'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bundle install

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;For jobs that would benefit from fiber-based processing, simply specify AsyncJob as the queue adapter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class SearchIndexingJob &amp;lt; ApplicationJob
  self.queue_adapter = :async_job # This job uses fibers
  queue_as :default

  def perform(document)
    # Your I/O-heavy code here
  end
end

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can continue using your existing queue adapter for other jobs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class CPUIntensiveJob &amp;lt; ApplicationJob
  # This job still uses your default queue adapter
  queue_as :default

  def perform(data)
    # CPU-intensive operations
  end
end

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more detailed setup instructions, check out the &lt;a href="https://socketry.github.io/async-job-adapter-active_job/guides/getting-started/index" rel="noopener noreferrer"&gt;AsyncJob Active Job Adapter documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmarking AsyncJob vs. SolidQueue for OpenSearch Operations
&lt;/h2&gt;

&lt;p&gt;To validate my hypothesis about AsyncJob’s benefits for I/O-bound operations, I created a comprehensive benchmarking project comparing AsyncJob (fiber-based) with SolidQueue (thread-based) for OpenSearch indexing operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Experiment Setup
&lt;/h3&gt;

&lt;p&gt;I created two nearly identical jobs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;JobTest1Job&lt;/code&gt; - Using SolidQueue with synchronous HTTP calls&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;JobTest2Job&lt;/code&gt; - Using AsyncJob with asynchronous HTTP calls&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both jobs perform the same task: indexing documents in OpenSearch. To simulate real-world conditions with network latency, I added a 3-second artificial delay to each OpenSearch request, results were drastically different. But the results here are without any simulated delay.&lt;/p&gt;

&lt;p&gt;The full code and detailed results are available in my &lt;a href="https://github.com/vikas-0/jobtest" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;========== BENCHMARK RESULTS ==========

----- Batch Size: 10 documents -----
SolidQueue (JobTest1Job):
  Avg Enqueue Time: 0.18s
  Avg Total Time: 1.19s
  Avg Throughput: 8.45 docs/second

AsyncJob (JobTest2Job):
  Avg Enqueue Time: 0.06s
  Avg Total Time: 1.06s
  Avg Throughput: 9.39 docs/second

Result: AsyncJob was 11.6% faster for 10 documents

----- Batch Size: 100 documents -----
SolidQueue (JobTest1Job):
  Avg Enqueue Time: 0.59s
  Avg Total Time: 1.6s
  Avg Throughput: 62.96 docs/second

AsyncJob (JobTest2Job):
  Avg Enqueue Time: 0.24s
  Avg Total Time: 1.25s
  Avg Throughput: 80.12 docs/second

Result: AsyncJob was 27.4% faster for 100 documents

----- Batch Size: 1000 documents -----
SolidQueue (JobTest1Job):
  Avg Enqueue Time: 4.8s
  Avg Total Time: 19.17s
  Avg Throughput: 54.78 docs/second

AsyncJob (JobTest2Job):
  Avg Enqueue Time: 2.25s
  Avg Total Time: 3.25s
  Avg Throughput: 307.48 docs/second

Result: AsyncJob was 489.1% faster for 1000 documents

========================================

========== RESOURCE USAGE METRICS ==========

----- SOLID_QUEUE Resource Usage -----
Memory Usage:
  Average: 128.69 MB
  Maximum: 177.19 MB
CPU Usage:
  Average per job: 28.4549 seconds
  Total CPU time: 74295.6439 seconds

----- ASYNC_JOB Resource Usage -----
Memory Usage:
  Average: 89.42 MB
  Maximum: 118.83 MB
CPU Usage:
  Average per job: 3.128 seconds
  Total CPU time: 5864.9192 seconds

----- Comparison -----
Memory Usage: AsyncJob uses -30.51% less memory than SolidQueue
CPU Usage: AsyncJob uses -92.11% less CPU time than SolidQueue

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: For solid queue, I have used 1 worker with 3 threads, which is a default configuration for solid queue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analyzing the Results
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Performance Scaling with Batch Size
&lt;/h3&gt;

&lt;p&gt;The most striking finding from the benchmarks is how AsyncJob’s advantage scales with batch size:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Batch Size&lt;/th&gt;
&lt;th&gt;Performance Advantage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10 documents&lt;/td&gt;
&lt;td&gt;AsyncJob was 11.6% faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100 documents&lt;/td&gt;
&lt;td&gt;AsyncJob was 27.4% faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1000 documents&lt;/td&gt;
&lt;td&gt;AsyncJob was 489.1% faster&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Key Insight:&lt;/strong&gt; AsyncJob’s performance advantage dramatically increases with the number of I/O operations. For small workloads, the difference is noticeable but modest. For large workloads, the difference is transformative.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resource Efficiency
&lt;/h3&gt;

&lt;p&gt;Beyond raw speed, the resource efficiency gains are equally impressive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Memory Usage:&lt;/strong&gt; AsyncJob uses 30.5% less memory than SolidQueue (89.42 MB vs 128.69 MB)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CPU Usage:&lt;/strong&gt; AsyncJob uses 92.1% less CPU time than SolidQueue (5,865 seconds vs 74,296 seconds)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This translates to significant infrastructure cost savings at scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Secret Sauce: Async HTTP Client
&lt;/h2&gt;

&lt;p&gt;A key part of my implementation was creating a fiber-aware HTTP client for OpenSearch. Here’s a simplified version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class AsyncOpenSearchClient
  def index(index:, id: nil, body:)
    # Return an Async task that performs the request asynchronously
    Async do |task|  
      # Make the request asynchronously
      response = Async::HTTP::Internet.post(url, headers, json_body)

      # Process response...
    end
  end
end

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This client ensures that while waiting for HTTP responses, other fibers can continue processing, maximizing throughput.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use AsyncJob
&lt;/h2&gt;

&lt;p&gt;Based on my benchmarks and some research (Google and AI), AsyncJob is ideal for:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Search Engine Indexing
&lt;/h3&gt;

&lt;p&gt;This was our primary pain point. AsyncJob transforms Elasticsearch/OpenSearch indexing by efficiently switching fibers during network I/O waits, allowing concurrent indexing operations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class SearchIndexingJob &amp;lt; ApplicationJob
  self.queue_adapter = :async_job
  queue_as :default

  def perform(document)
    # Each index operation is an I/O operation where AsyncJob can yield
    search_client.index(
      index: "content",
      id: document.id,
      body: document.to_indexed_json
    )
  end
end

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. API Integrations
&lt;/h3&gt;

&lt;p&gt;Jobs that make external API calls are perfect candidates for AsyncJob:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class NotificationJob &amp;lt; ApplicationJob
  self.queue_adapter = :async_job
  queue_as :default

  def perform(user_id, message)
    # Multiple API calls can run concurrently
    push_notification_service.send(user_id, message)
    slack_service.notify(message)
    analytics_service.track("notification_sent", user_id)
  end
end

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. LLM Operations
&lt;/h3&gt;

&lt;p&gt;Large Language Model API calls typically have high latency, making them ideal for AsyncJob:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class AIProcessingJob &amp;lt; ApplicationJob
  self.queue_adapter = :async_job
  queue_as :default

  def perform(documents)
    # Process multiple documents concurrently
    documents.each do |doc|
      summary = llm_client.summarize(doc.content)
      doc.update(ai_summary: summary)
    end
  end
end

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When NOT to Use AsyncJob
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CPU-Intensive Operations&lt;/strong&gt; : If your job is CPU-bound (complex calculations, image processing), traditional thread-based queues may perform better.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Very Short-Running Jobs&lt;/strong&gt; : For jobs that complete in milliseconds with minimal I/O, the overhead of fiber management might not be worth it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Jobs with Non-Fiber-Aware Dependencies&lt;/strong&gt; : Some gems and libraries aren’t fiber-aware and may block fibers, negating AsyncJob’s benefits.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Jobs Requiring Robust Error Handling&lt;/strong&gt; : AsyncJob currently lacks some of the error handling capabilities found in more mature job processors.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Important Considerations: Error Handling with AsyncJob
&lt;/h2&gt;

&lt;p&gt;While AsyncJob offers impressive performance benefits, it’s important to be aware of its current limitations in error handling:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Limited Built-in Error Handling&lt;/li&gt;
&lt;li&gt;Manual Error Logging Required&lt;/li&gt;
&lt;li&gt;Monitoring Challenges&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion: A Game-Changer for I/O-Heavy Workloads
&lt;/h2&gt;

&lt;p&gt;For applications with significant I/O-bound job processing needs, AsyncJob represents a paradigm shift in performance and efficiency. My benchmarks show that it’s not just marginally better—it can be 5x faster while using 30% less memory and 90% less CPU time.&lt;/p&gt;

&lt;p&gt;The best part? You can gradually adopt AsyncJob for specific jobs without changing your entire infrastructure. Start by identifying your most I/O-intensive jobs and convert them first to see immediate benefits.&lt;/p&gt;

&lt;p&gt;If your Rails application is struggling with I/O-bound job processing, AsyncJob might just be the solution you’ve been looking for.&lt;/p&gt;

&lt;p&gt;(Note: I have not used it extensively in production yet, but the benchmarks show promising results.)&lt;/p&gt;

</description>
      <category>rails</category>
      <category>activejob</category>
    </item>
    <item>
      <title>How to Use Tiptap's Collaboration Feature with Rails Action Cable</title>
      <dc:creator>Vikas Kumar</dc:creator>
      <pubDate>Tue, 18 Jun 2024 15:25:00 +0000</pubDate>
      <link>https://dev.to/vikas/how-to-use-tiptaps-collaboration-feature-with-rails-action-cable-2hg0</link>
      <guid>https://dev.to/vikas/how-to-use-tiptaps-collaboration-feature-with-rails-action-cable-2hg0</guid>
      <description>&lt;p&gt;In this post, we’ll walk through setting up Tiptap’s collaboration feature with Rails Action Cable and ReactJs. Tiptap is a powerful headless editor built on ProseMirror, and when combined with Y.js, it allows for real-time collaborative editing. We’ll use Mantine component libaray, but it’s not mandatory for this setup.&lt;/p&gt;

&lt;p&gt;If you prefer to dive directly into the code, check out the example on &lt;a href="https://github.com/vikas-0/collab_demo"&gt;Github&lt;/a&gt;&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;a href="https://www.youtube-nocookie.com/embed/HXpudWU5FxQ" rel="noopener noreferrer"&gt;
      youtube-nocookie.com
    &lt;/a&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Ensure you have the following installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ruby on Rails&lt;/li&gt;
&lt;li&gt;Redis&lt;/li&gt;
&lt;li&gt;Node.js and Yarn&lt;/li&gt;
&lt;li&gt;Your preferred mehtod of React Setup with Rails&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Setting Up Mantine
&lt;/h3&gt;

&lt;p&gt;First, we’ll set up Mantine for styling. Follow the &lt;a href="https://mantine.dev/guides/vite/"&gt;Mantine guide for Vite&lt;/a&gt; to install the necessary packages: (Same method worked for me using esbuild in my setup. You can do it you own way or choose not to use Mantine)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add @mantine/core @mantine/hooks @mantine/tiptap @tabler/icons-react @tiptap/react @tiptap/extension-link @tiptap/starter-kit @tiptap/extension-placeholder @tiptap/extension-collaboration-cursor @tiptap/extension-collaboration yjs y-prosemirror
yarn add &lt;span class="nt"&gt;--dev&lt;/span&gt; postcss postcss-preset-mantine postcss-simple-vars
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: This setup includes both Mantine and Tiptap. If you do not require Mantine, skip installing Mantine-related dependencies.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 2: Install Rails Dependencies
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bundle add redis y-rb_actioncable y-rb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are installing Y.js adapter for Ruby and Action Cable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Configure Tiptap with Collaboration
&lt;/h3&gt;

&lt;p&gt;In the Tiptap setup, configure the StarterKit with history: false as the Collaboration extension comes with its own history management. Additionally, we’ll add a random color generator for collaboration cursors.&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getRandomColor&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;colors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#ff901f&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#ff2975&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#f222ff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#8c1eff&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;selectedIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&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="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectedIndex&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;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useEditor&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="nx"&gt;StarterKit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;history&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;span class="nx"&gt;Underline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;Superscript&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;SubScript&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;Highlight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;TextAlign&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;heading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;paragraph&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;Placeholder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This is placeholder&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
            &lt;span class="nx"&gt;Collaboration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;document&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="c1"&gt;// Configure Y.Doc for collaboration&lt;/span&gt;
            &lt;span class="p"&gt;}),&lt;/span&gt;
            &lt;span class="nx"&gt;CollaborationCursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Vikas&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getRandomColor&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Code to connect with websocket provided by ActionCable. Don’t worry about the channel creation now, we will create it later. Assuming channel name will be &lt;code&gt;SyncChannel&lt;/code&gt; we will add following code. (Here id is hardcoded, as this is just a demo. we won’t be using proper auth in backend as well to keep things simple)&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;// ... other imports&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;createConsumer&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;@rails/actioncable&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;WebsocketProvider&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;@y-rb/actioncable&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;consumer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createConsumer&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;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Doc&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;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebsocketProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SyncChannel&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;id&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;span class="c1"&gt;// ... other codes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see full frontend code in &lt;a href="https://github.com/vikas-0/collab_demo/blob/main/app/javascript/App.jsx"&gt;App.jsx&lt;/a&gt;. This contains everything in a single file which is not great but good enough for this case.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Set Up Rails Action Cable
&lt;/h3&gt;

&lt;p&gt;Create a new channel name &lt;code&gt;SyncChannel&lt;/code&gt; at &lt;code&gt;app/channels/sync_channel.rb&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# frozen_string_literal: true&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SyncChannel&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationCable&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Channel&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Actioncable&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Sync&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;subscribed&lt;/span&gt;
    &lt;span class="c1"&gt;# initiate sync &amp;amp; subscribe to updates, with optional persistence mechanism&lt;/span&gt;
    &lt;span class="n"&gt;sync_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;save_doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# broadcast update to all connected clients on all servers&lt;/span&gt;
    &lt;span class="n"&gt;sync_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;doc&lt;/span&gt;
    &lt;span class="vi"&gt;@doc&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="nb"&gt;load&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;load_doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;session&lt;/span&gt;
    &lt;span class="vi"&gt;@session&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;REDIS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unpack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"C*"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;save_doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;REDIS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"C*"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This has Redis initialized as REDIS, replace it with your Redis variable name. We also created a Session model for &lt;code&gt;sync_for&lt;/code&gt; mehtod. You can check documentation for sync_for &lt;a href="https://y-crdt.github.io/yrb-actioncable/Y/Actioncable/Sync.html#sync_for-instance_method"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# frozen_string_literal: true&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Session&lt;/span&gt;
  &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_s&lt;/span&gt;
    &lt;span class="s2"&gt;"sessions:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally &lt;code&gt;ApplicationCable::Connection&lt;/code&gt; will be as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ApplicationCable&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActionCable&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Connection&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
    &lt;span class="n"&gt;identified_by&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;
      &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SecureRandom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 6: Add Styles for Collaboration Cursor (Option)
&lt;/h3&gt;

&lt;p&gt;Everything should be working by now. In this step the cursor was looking odd, so some &lt;a href="https://github.com/vikas-0/collab_demo/blob/main/app/javascript/App.css"&gt;CSS&lt;/a&gt; can be add to make it look good.&lt;/p&gt;

&lt;p&gt;Finally you can run your rails server and it should be good to go once we add all missing piecies specially authorisation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;By following these steps, you should have a real-time collaborative editor up and running using Tiptap, Y.js, and Rails Action Cable. While we used Mantine for styling in this demo, you can customize the styling as per your requirements. This setup provides a robust foundation for building collaborative applications with rich text editing capabilities.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>react</category>
      <category>actioncable</category>
      <category>tiptap</category>
    </item>
    <item>
      <title>Seamless Remote Development with Any IDE Using Unison for Bidirectional SSH Sync</title>
      <dc:creator>Vikas Kumar</dc:creator>
      <pubDate>Wed, 15 May 2024 06:21:00 +0000</pubDate>
      <link>https://dev.to/vikas/seamless-remote-development-with-any-ide-using-unison-for-bidirectional-ssh-sync-1dd4</link>
      <guid>https://dev.to/vikas/seamless-remote-development-with-any-ide-using-unison-for-bidirectional-ssh-sync-1dd4</guid>
      <description>&lt;p&gt;If your development environment is on a remote server, you might need to code on the remote machine itself to see the effects of your changes in real time. This scenario is fairly common these days as applications become more complex, and setting up a local development environment requires extensive configuration or mocking of the resources used in the app.&lt;/p&gt;

&lt;p&gt;In this case, you are left with very few options for code editors. Either you have to use CLI-based editors such as Vim, or you can use VSCode with the &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh"&gt;Remote SSH extension&lt;/a&gt;. Even with the extension, there are some issues related to code analysis and code completion. These processes have to happen on the remote machine, making your powerful local PC underutilized. And if you want to use Zed or Xcode, you are out of luck.&lt;/p&gt;

&lt;p&gt;So, the solution is to have a local copy that is synced with the remote SSH directory. You can use several tools for this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Rsync&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unidirectional sync, which might be fine for development as you will use the local machine's copy to manage changes on the SSH server.&lt;/li&gt;
&lt;li&gt;Does not support file deletion.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;&lt;strong&gt;SSHFS&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Limited support on macOS.&lt;/li&gt;
&lt;li&gt;Requires kernel changes, making it impractical for use on some machines.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Unison&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supports bidirectional sync.&lt;/li&gt;
&lt;li&gt;Handles file deletions.&lt;/li&gt;
&lt;li&gt;Fault-tolerant: even if the connection breaks, you can restart it, and it will continue syncing from the last known point.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This leaves Unison as the ideal choice for me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/bcpierce00/unison"&gt;Unison&lt;/a&gt; has fairly good documentation; you can go ahead and check their documents and explore on your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Unison
&lt;/h2&gt;

&lt;p&gt;You need to install Unison on both the host and remote machine. If you don't have sudo access on the remote machine, don't worry; you can download the binary and keep it anywhere.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Installing Unison on Mac local machine:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;brew install unison&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;brew install autozimu/homebrew-formulas/unison-fsmonitor&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For Linux, you can follow the &lt;a href="https://www.cis.upenn.edu/~bcpierce/unison/download/releases/stable/"&gt;official guide&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make sure to create a local folder to sync code from the remote machine.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Run a test connection:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Example command: &lt;code&gt;unison -testServer ssh://user@remotehostname/path/to/folder /path/to/folder&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If you get an error that Unison is not found on the remote server, specify the exact path to Unison using &lt;code&gt;-servercmd&lt;/code&gt;. For example: &lt;code&gt;unison -testServer ssh://user@remotehostname/path/to/folder /path/to/folder -servercmd /home/path/to/unison/bin/unison&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Final command for syncing:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Once the connection test is successful, start syncing with the final command:
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  unison ssh://user@remotehostname/path/to/folder /path/to/folder -servercmd /home/path/to/unison/bin/unison -ignore "BelowPath node_modules" -ignore "BelowPath .git" -force newer -repeat watch
&lt;/code&gt;&lt;/pre&gt;



&lt;ul&gt;
&lt;li&gt;This command will sync all files and continue monitoring for further changes in the background while you develop. If you want to know the meaning of flags used here like &lt;code&gt;ignore&lt;/code&gt;, &lt;code&gt;force&lt;/code&gt; etc, you can check &lt;a href="https://github.com/bcpierce00/unison/wiki"&gt;Unison user mannual&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can use any code editor to modify the local copy, and Unison will automatically sync the changes.&lt;/p&gt;

</description>
      <category>ssh</category>
      <category>remotedevelopment</category>
      <category>unison</category>
    </item>
    <item>
      <title>Stop using serverless-webpack for AWS Lambda</title>
      <dc:creator>Vikas Kumar</dc:creator>
      <pubDate>Thu, 06 Oct 2022 10:08:00 +0000</pubDate>
      <link>https://dev.to/vikas/stop-using-serverless-webpack-for-aws-lambda-2k90</link>
      <guid>https://dev.to/vikas/stop-using-serverless-webpack-for-aws-lambda-2k90</guid>
      <description>&lt;p&gt;I see that nodejs lambda projects are built using serverless and often include serverless-webpack. It is used to implement babel and get the latest javascript syntaxes, especially module and top-level awaits.&lt;/p&gt;

&lt;p&gt;But as per this &lt;a href="https://aws.amazon.com/about-aws/whats-new/2022/01/aws-lambda-es-modules-top-level-await-node-js-14/"&gt;blog post&lt;/a&gt;, the AWS lambda environment already supports these features, so we should no longer need to use serverless-webpack.&lt;/p&gt;

&lt;p&gt;There are some cons that I face while using webpack in serverless.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Code is transpiled (and optionally minified), making it challenging to debug from logs, as line numbers and function names may not be the same per your development environment.&lt;/li&gt;
&lt;li&gt;Using ESM only module is not straightforward. Such as node-fetch and d3, and the ESM-only module list is growing daily.&lt;/li&gt;
&lt;li&gt;There could also be a performance impact as the code will be converted to commonJS, and this &lt;a href="https://aws.amazon.com/blogs/compute/using-node-js-es-modules-and-top-level-await-in-aws-lambda/"&gt;benchmark test&lt;/a&gt; shows that commonsJS could perform 43% worse than ESM.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are other benefits of babel and webpack besides transpiling to commonJS. But these are mostly catered towards browsers and not serverside usage.&lt;/p&gt;

&lt;p&gt;How to use ESM in serverless? Just add &lt;code&gt;"type": "module"&lt;/code&gt; in &lt;code&gt;pacakge.json&lt;/code&gt; in it will work in node 14.x and node 16.x.&lt;/p&gt;

</description>
      <category>awslambda</category>
      <category>node</category>
    </item>
    <item>
      <title>Journey of building a game using the Flutter</title>
      <dc:creator>Vikas Kumar</dc:creator>
      <pubDate>Sat, 19 Feb 2022 03:47:00 +0000</pubDate>
      <link>https://dev.to/vikas/journey-of-building-a-game-using-the-flutter-22ij</link>
      <guid>https://dev.to/vikas/journey-of-building-a-game-using-the-flutter-22ij</guid>
      <description>&lt;p&gt;For the last few weeks, I have been working on a React Native project for work. So this was my first experience writing “real” mobile apps. Before that, I only wrapped PWA’s as APK and called myself a mobile developer 😎.&lt;/p&gt;

&lt;p&gt;React-Native came naturally to me after climbing some learning curves as a React Developer. So, now I wanted to check out the buzz around Flutter.&lt;/p&gt;

&lt;p&gt;So last weekend was a fine sunny day which is quite pleasing in the late winter season. It might not be winter from many people’s standard. I opened the Flutter documentation getting started page. The installation file was quite big compared to react-native and it made my expectations high.&lt;/p&gt;

&lt;p&gt;At this point, I knew nothing about dart and Flutter, how it works and how to write code. But the Flutter had an excellent &lt;a href="https://docs.flutter.dev/get-started/flutter-for/react-native-devs"&gt;write-up&lt;/a&gt; comparing React-Native to Dart and Flutter. It helped me directly dive into building things without learning anything. I got pumped up to create something; I thought of a real simple application/game that is just sorting a list of cities so that traversing through all cities in order will be optimal. It’s not a fair game from the graphics standard, 😥 but good enough for me.&lt;/p&gt;

&lt;p&gt;The app uses a list of cities downloaded from &lt;a href="https://simplemaps.com/data/in-cities"&gt;simplemaps.com&lt;/a&gt; and used a geometry formula to calculate the distance. After a day of playing out, I was able to finish it with the help of a lot of google, stack overflow, and 3rd party packages.&lt;/p&gt;

&lt;p&gt;It almost feels like magic that I still don’t know dart language correctly, but my app is running. Flutter dev tools are excellent compared to React-Native, which helped me identify and fix issues more quickly.&lt;/p&gt;

&lt;p&gt;I published my app just for fun ☺️ on the &lt;a href="https://play.google.com/store/apps/details?id=com.distoptim.geekyhub"&gt;PlayStore&lt;/a&gt;, and if you are interested, you can also check out the &lt;a href="https://github.com/vikas-0/Distoptim"&gt;code&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>flutter</category>
    </item>
    <item>
      <title>Animate SVG in React Native</title>
      <dc:creator>Vikas Kumar</dc:creator>
      <pubDate>Sun, 06 Feb 2022 08:00:00 +0000</pubDate>
      <link>https://dev.to/vikas/animate-svg-in-react-native-4njo</link>
      <guid>https://dev.to/vikas/animate-svg-in-react-native-4njo</guid>
      <description>&lt;p&gt;Here, by animating SVG, I mean to change the property of SVG elements dynamically, which will look live-like.&lt;/p&gt;

&lt;p&gt;In react native, we can generate/render an SVG using the &lt;a href="https://github.com/react-native-svg/react-native-svg"&gt;react-native-svg&lt;/a&gt; library. A complex SVG comprises many more minor elements that could be animated individually. But here, for example, we will take only one piece, a circle.&lt;/p&gt;

&lt;p&gt;The following code will draw a circle with a radius of 50 units.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Svg&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="si"&gt;}&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="nc"&gt;Circle&lt;/span&gt; &lt;span class="na"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"55"&lt;/span&gt; &lt;span class="na"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"55"&lt;/span&gt; &lt;span class="na"&gt;r&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"50"&lt;/span&gt; &lt;span class="na"&gt;stroke&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"black"&lt;/span&gt; &lt;span class="na"&gt;strokeWidth&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="si"&gt;}&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="nc"&gt;Svg&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suppose we want to animate it to become large and small. To achieve this, I will use &lt;a href="https://docs.swmansion.com/react-native-reanimated/"&gt;React Native Reanimated&lt;/a&gt;. To learn more about it, you can check out its documentation.&lt;/p&gt;

&lt;p&gt;Logically, I am trying to increase or decrease the radius.&lt;/p&gt;

&lt;p&gt;Since the radius value is a prop, I will use &lt;code&gt;useAnimatedProps&lt;/code&gt;. But, first of all, convert Circle to an animated component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AnimatedCircle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Animated&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createAnimatedComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Circle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, I can re-write component as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Svg&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="si"&gt;}&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="nc"&gt;AnimatedCircle&lt;/span&gt; &lt;span class="na"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"55"&lt;/span&gt; &lt;span class="na"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"55"&lt;/span&gt; &lt;span class="na"&gt;r&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"50"&lt;/span&gt; &lt;span class="na"&gt;stroke&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"black"&lt;/span&gt; &lt;span class="na"&gt;strokeWidth&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="si"&gt;}&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="nc"&gt;Svg&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next step is to store the stroke width and radius. width can be stored in a simple constat, but for the radius we will use &lt;a href="https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/shared-values"&gt;&lt;code&gt;useSharedValue&lt;/code&gt;&lt;/a&gt;, so that it can be used by woklet to animate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default &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;radius&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSharedValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&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;strokeWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Svg&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="si"&gt;}&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="nc"&gt;AnimatedCircle&lt;/span&gt;
        &lt;span class="na"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;radius&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;+&lt;/span&gt; &lt;span class="nx"&gt;strokeWidth&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;radius&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;+&lt;/span&gt; &lt;span class="nx"&gt;strokeWidth&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;r&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;radius&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="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;stroke&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"black"&lt;/span&gt;
        &lt;span class="na"&gt;strokeWidth&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strokeWidth&lt;/span&gt;&lt;span class="si"&gt;}&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="nc"&gt;Svg&lt;/span&gt;&lt;span class="p"&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;Here, I need some event or action to trigger the radius change. I’ll use a button press. (withSpring is default provided animation which is not necessary to use but this looks cool 🤞)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"contained"&lt;/span&gt; &lt;span class="na"&gt;onPress&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;radius&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;lt;&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;radius&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;=&lt;/span&gt; &lt;span class="nf"&gt;withSpring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;radius&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;=&lt;/span&gt; &lt;span class="nf"&gt;withSpring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&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="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  Press
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll notice that even after pressing the button, nothing happens. It is because change of sharedValue doesn’t trigger re-render of the react component. finally animated props comes into the picture. Instead of passing prop directly, we will pass it using animated prop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;animatedProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useAnimatedProps&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="na"&gt;cx&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;radius&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;+&lt;/span&gt; &lt;span class="nx"&gt;strokeWidth&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="na"&gt;cy&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;radius&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;+&lt;/span&gt; &lt;span class="nx"&gt;strokeWidth&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="na"&gt;r&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;radius&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="s2"&gt;`&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;


&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Svg&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="si"&gt;}&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="nc"&gt;AnimatedCircle&lt;/span&gt;
    &lt;span class="na"&gt;animatedProps&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;animatedProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;stroke&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"black"&lt;/span&gt;
    &lt;span class="na"&gt;strokeWidth&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strokeWidth&lt;/span&gt;&lt;span class="si"&gt;}&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="nc"&gt;Svg&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result, is something like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9eDnE_0m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://www.geekyhub.in/post/animate-svg-using-react-native-renanimated-2/circle-animation.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9eDnE_0m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://www.geekyhub.in/post/animate-svg-using-react-native-renanimated-2/circle-animation.gif" width="296" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a relatively simple example, but I hope I successfully demonstrated the possibilities. Here is the &lt;a href="https://gist.github.com/vikas-0/24c785c2a178a790b3b7352b400cc400"&gt;link&lt;/a&gt; of complete code of the result if you are interested.&lt;/p&gt;

</description>
      <category>reactnative</category>
    </item>
    <item>
      <title>Handling multiple stores in a React-Redux application</title>
      <dc:creator>Vikas Kumar</dc:creator>
      <pubDate>Mon, 11 Oct 2021 18:57:00 +0000</pubDate>
      <link>https://dev.to/vikas/handling-multiple-stores-in-a-react-redux-application-13jb</link>
      <guid>https://dev.to/vikas/handling-multiple-stores-in-a-react-redux-application-13jb</guid>
      <description>&lt;p&gt;In a react-redux application, it is a good practice to have only one redux store. But if for some weird/“special” reason if you have to have more than one store, you will face some problems.&lt;/p&gt;

&lt;p&gt;The most common problem is that if we wrap a component with a provider and then wrap a child component with another provider, it’s not easy to subscribe to the store of top-level provider.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Component1&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;store&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;store1&lt;/span&gt;&lt;span class="si"&gt;}&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="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;store&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;store2&lt;/span&gt;&lt;span class="si"&gt;}&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="nc"&gt;Component2&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="nc"&gt;Provider&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="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&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;It’s so confusing that within a few iterations of development, you’ll find yourself using providers on each component, and not being able to read values from both the stores in a single component will frustrate you.&lt;/p&gt;

&lt;p&gt;To manage this elegantly, we can do some setup which will ease the things.&lt;/p&gt;

&lt;p&gt;For this, we will need &lt;code&gt;react-redux 7&lt;/code&gt; or greater. Because versions older than it doesn’t use react’s context API. And we will be using contexts to access multiple stores without wrapping with the providers again and again.&lt;/p&gt;

&lt;p&gt;Create a context for each store. You can also import &lt;code&gt;ReactReduxContext&lt;/code&gt; from &lt;code&gt;react-redux&lt;/code&gt; and use it for one of the stores, which you want to make default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store1Context&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="nf"&gt;createContext&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;store2Context&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="nf"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now wrap the root component of the react application with a provider for each store, passing the contexts as props.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;store&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;store1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;store1Context&lt;/span&gt;&lt;span class="si"&gt;}&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="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;store&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;store2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;store2Context&lt;/span&gt;&lt;span class="si"&gt;}&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="nc"&gt;App&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="nc"&gt;Provider&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="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to create custom dispatch and selector hooks. If you use the default hooks (&lt;code&gt;useSelector&lt;/code&gt;, &lt;code&gt;useDispatch&lt;/code&gt;), it will use the store with default context, if any.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;useStore1Dispatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createDispatchHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store1Context&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;useStore1Selector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSelectorHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store1Context&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;useStore2Dispatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createDispatchHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store2Context&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;useStore2Selector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSelectorHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store2Context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From further development, you can use these custom selector and dispatch hooks to use the preferred store in any of the components throughout the application.&lt;/p&gt;

&lt;p&gt;If you prefer to connect HOC, then you can do&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mapStateToProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mapDispatchtoProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;mergeProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;store1Context&lt;/span&gt;&lt;span class="p"&gt;})(&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me know if you have any suggestions or questions. Thanks&lt;/p&gt;

</description>
      <category>react</category>
      <category>redux</category>
    </item>
    <item>
      <title>Difference between 'useEffect' and calling function directly inside a component.</title>
      <dc:creator>Vikas Kumar</dc:creator>
      <pubDate>Sun, 09 May 2021 12:32:00 +0000</pubDate>
      <link>https://dev.to/vikas/difference-between-useeffect-and-calling-function-directly-inside-a-component-3m96</link>
      <guid>https://dev.to/vikas/difference-between-useeffect-and-calling-function-directly-inside-a-component-3m96</guid>
      <description>&lt;p&gt;In React, the useEffect hook is pretty straightforward. But its simplicity sometimes makes me forget its actual function. I remembered useEffect simply as something which takes a callback and a dependency array as arguments, and it will execute the callback whenever the dependency array is changed. And in case of no dependency array, it will run the callback each time the component renders.&lt;/p&gt;

&lt;p&gt;But then what will be the difference between the following two cases.&lt;/p&gt;

&lt;p&gt;To find out, I have created a small React application with a couple of props and states of type number and four buttons to increment those numbers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;App.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;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="nx"&gt;TestComponent&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;./TestComponent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;prop1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setProp1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;prop2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setProp2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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;return &lt;/span&gt;&lt;span class="p"&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;&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="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setProp1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&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="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Prop 1&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;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="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setProp2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&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="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Prop 2&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="nc"&gt;TestComponent&lt;/span&gt; &lt;span class="na"&gt;prop1&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;prop1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;prop2&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;prop2&lt;/span&gt;&lt;span class="si"&gt;}&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;TestComponent.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;useEffect&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;TestComponent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;prop1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prop2&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setState1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setState2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="nf"&gt;useEffect&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rendered - useEffect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prop1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prop2&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;someImportantWork&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rendered - functionCall&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prop1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prop2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;someImportantWork&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="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="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setState1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&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="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;State 1&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;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="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setState2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&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="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;State 2&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;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Prop 1: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;prop1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&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;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Prop 2: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;prop2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&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;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;State 1: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&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;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;State 2: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&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="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;TestComponent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see in following that both &lt;code&gt;console.log&lt;/code&gt; statement runs whenever we update &lt;code&gt;state&lt;/code&gt; or &lt;code&gt;prop&lt;/code&gt;.&lt;/p&gt;


        
      
    

&lt;p&gt;But I think we are missing something because both seems to be same. So let’s slow down the rendering.&lt;/p&gt;

&lt;p&gt;To slow down the rendering I added a very long loopin inside &lt;code&gt;return&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;useEffect&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10999999&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;TestComponent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;prop1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prop2&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&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;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&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="nf"&gt;setState1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&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="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&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="nf"&gt;setState2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&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="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;State&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;x&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="kc"&gt;null&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;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Prop&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;prop1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the delay we can clearly see that expression inside useEffect is always excuted after expression in the fucntion.&lt;/p&gt;


        
      
    

&lt;p&gt;It is because the definition of &lt;code&gt;useEffect&lt;/code&gt; stated at the beginning of this post is incomplete. useEffect not only executes the callback on each render (depending upon the dependency array) but also ensures that rendering has been completed. That’s why useEffect’s &lt;code&gt;console.log&lt;/code&gt; is delayed.&lt;/p&gt;

&lt;p&gt;This should not be a problem if you are doing some small calculation or, as in this example, logging. But if you are using &lt;code&gt;ref&lt;/code&gt; to access the element, you must ensure that render has happened; else, you may get the wrong reference.&lt;/p&gt;

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