<?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>Forem: Viktor Shcheglov</title>
    <description>The latest articles on Forem by Viktor Shcheglov (@shcheglov).</description>
    <link>https://forem.com/shcheglov</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%2F1261466%2F7918112f-b87b-4ca7-ad6f-5778f0e558d2.jpg</url>
      <title>Forem: Viktor Shcheglov</title>
      <link>https://forem.com/shcheglov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/shcheglov"/>
    <language>en</language>
    <item>
      <title>How To Use Chrome UX Report To Improve Your Site Performance</title>
      <dc:creator>Viktor Shcheglov</dc:creator>
      <pubDate>Mon, 12 Aug 2024 16:38:02 +0000</pubDate>
      <link>https://forem.com/shcheglov/how-to-use-chrome-ux-report-to-improve-your-site-performance-160i</link>
      <guid>https://forem.com/shcheglov/how-to-use-chrome-ux-report-to-improve-your-site-performance-160i</guid>
      <description>&lt;p&gt;Avoid turning off potential site visitors. Take advantage of the Chrome UX Reports to ensure your site's peak performance with this guide.&lt;/p&gt;

&lt;p&gt;Measuring success in website performance is a tricky task for small business owners.&lt;/p&gt;

&lt;p&gt;It can be easy to apply the same approach that works when evaluating viability throughout a company.&lt;/p&gt;

&lt;p&gt;Black and white, hard and fast numbers. Results.&lt;/p&gt;

&lt;p&gt;The truth of website performance is more of a multilayered exploration of RUM (Real User Measurements) within the context of the web at large.&lt;/p&gt;

&lt;p&gt;Looking at RUM such as performance, page load, and page views gives a detailed picture of hard data.&lt;/p&gt;

&lt;p&gt;However, RUM data is only part of a bigger equation to measure a website’s impact and success.&lt;/p&gt;

&lt;p&gt;The CrUX Of The Matter: The State Of The Web As Experienced By Real Users&lt;br&gt;
To be truly informative and deliver actionable data, you must balance users’ experiences on your site within the scope of user experience across the internet.&lt;/p&gt;

&lt;p&gt;Stepping back lets businesses understand their site’s performance and know where those metrics land within a vast array of parameters.&lt;/p&gt;

&lt;p&gt;This is where the Chrome UX Report enters the fray.&lt;/p&gt;

&lt;p&gt;Making Web Performance Data On A Broad Scale Accessible To The Masses&lt;br&gt;
First established by Google in 2017, the Chrome UX Report is a publicly available dataset of real user measurements.&lt;/p&gt;

&lt;p&gt;Also known as the CrUX report, it gathers website performance data for Chrome users from millions of websites.&lt;/p&gt;

&lt;p&gt;If that data were only compiled, it would be an incredible – but difficult to utilize – resource. When paired with the right program, however, the data is transformed.&lt;/p&gt;

&lt;p&gt;When put to use correctly, the CrUX Report transforms an immense collection of web performance data into a clear and accessible resource.&lt;/p&gt;

&lt;p&gt;To better understand the data compiled in the CrUX Report and how best to utilize it, we need to step back.&lt;/p&gt;

&lt;p&gt;It’s time to review Chrome’s Core Web Vitals.&lt;/p&gt;

&lt;p&gt;Page Experience And User Experience Are A Direct Result Of The Health Of A Website&lt;br&gt;
Google is always seeking innovative and cutting-edge ways to provide users with a smooth, crisp online experience.&lt;/p&gt;

&lt;p&gt;A significant cornerstone of that effort is Google’s work empowering website owners to maximize their sites.&lt;/p&gt;

&lt;p&gt;When website owners deliver user-friendly, beneficial sites effectively, everyone wins.&lt;/p&gt;

&lt;p&gt;The only way to achieve success in an endeavor, though, is to know what the rules and standards are.&lt;/p&gt;

&lt;p&gt;In May 2020, Google released a new set of metrics to help evaluate website performance as it impacted user experience.&lt;/p&gt;

&lt;p&gt;These were its Core Web Vitals.&lt;/p&gt;

&lt;p&gt;The goal was to clear away minor and arbitrary details muddying up the water.&lt;/p&gt;

&lt;p&gt;To do so, Google narrowed down a website’s user experience score to three core measurements:&lt;/p&gt;

&lt;p&gt;LCP (Largest Contentful Paint).&lt;br&gt;
FID (First Input Delay).&lt;br&gt;
CLS (Cumulative Layout Shift).&lt;br&gt;
Core Web Vitals are anchored on the crucial role of page experience in the more extensive user experience.&lt;/p&gt;

&lt;p&gt;How does Google define page experience?&lt;/p&gt;

&lt;p&gt;For its purposes, page experience measures how users perceive their experience interacting with an individual web page.&lt;/p&gt;

&lt;p&gt;Building off of that, they define CWV as:&lt;/p&gt;

&lt;p&gt;“A set of real-world, user-centered metrics that quantify key aspects of the user experience. They measure dimensions of web usability such as load time, interactivity, and the stability of content as it loads.”&lt;/p&gt;

&lt;p&gt;When merged, the three elements of Core Web Vitals – LCP, FID, and CLS – deliver powerful insight.&lt;/p&gt;

&lt;p&gt;As a whole, CWV results provide a precise picture of a user’s page experience on an individual website.&lt;/p&gt;

&lt;p&gt;This page experience ultimately defines their user experience as a whole when utilizing the Google search engine.&lt;/p&gt;

&lt;p&gt;A year after the initial announcement, it was made permanent.&lt;/p&gt;

&lt;p&gt;Google finalized the integration of the new metrics with the permanent inclusion of Core Web Vitals into its algorithm.&lt;/p&gt;

&lt;p&gt;Core Web Vitals zero in on website speed, responsiveness, and visual stability. However, it should be noted that they are part of a vast picture.&lt;/p&gt;

&lt;p&gt;The Google search algorithm is always evolving, a challenge that demands vigilance on the part of professional SEO operators.&lt;/p&gt;

&lt;p&gt;There were once reportedly more than 200 ranking factors.&lt;/p&gt;

&lt;p&gt;Nowadays, some are weighted far more heavily and studied throughout the industry.&lt;/p&gt;

&lt;p&gt;These factors continue to evolve as Google adapts to new data and user behavior.&lt;/p&gt;

&lt;p&gt;The best practice is to review its ranking factors on a year-to-year basis.&lt;/p&gt;

&lt;p&gt;Breaking Down The Google Search Algorithm&lt;br&gt;
Despite the blanket of lore that has covered it over the years, the Google search algorithm has a definitive foundation.&lt;/p&gt;

&lt;p&gt;It is anchored by the company’s commitment to ensuring a smooth and efficient search experience for all users.&lt;/p&gt;

&lt;p&gt;Google continuously molds its search algorithm year-round to best meet the present and future demands of the global population.&lt;/p&gt;

&lt;p&gt;The Google search algorithm focuses on a litany of factors that perpetually fluctuates.&lt;/p&gt;

&lt;p&gt;In response, the SEO industry has consistently honed in on the key elements to focus on every year.&lt;/p&gt;

&lt;p&gt;Knowing where to prioritize your focus when designing your website empowers you to achieve an optimal presence in the rankings.&lt;/p&gt;

&lt;p&gt;These can include, but are not limited to:&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Send messages to the client in real time using NodeJS and Server-Sent Events</title>
      <dc:creator>Viktor Shcheglov</dc:creator>
      <pubDate>Thu, 01 Aug 2024 10:13:10 +0000</pubDate>
      <link>https://forem.com/shcheglov/send-messages-to-the-client-in-real-time-using-nodejs-and-server-sent-events-3bi2</link>
      <guid>https://forem.com/shcheglov/send-messages-to-the-client-in-real-time-using-nodejs-and-server-sent-events-3bi2</guid>
      <description>&lt;p&gt;Overview&lt;br&gt;
Server-Sent Events(SSE) technology, which allows sending information from server to client in real time, is based on HTTP protocol.&lt;/p&gt;

&lt;p&gt;On the client side server-sent events API provides EventSource interface (part of HTML5 standard), through which a persistent connection to HTTP server is opened.&lt;/p&gt;

&lt;p&gt;The HTTP server sends events in text/event-stream format. The connection remains open until the EventSource.close() method is called.&lt;/p&gt;

&lt;p&gt;Limitations:&lt;/p&gt;

&lt;p&gt;Only receiving data from the server is possible (unidirectional data stream, unlike WebSockets);&lt;br&gt;
Data can only be transmitted in UTF-8 format (non-binary data).&lt;br&gt;
Possible advantages:&lt;/p&gt;

&lt;p&gt;Works over HTTP, which means that clients will not have connection problems when connected via proxies that do not support other connections (such as WebSockets);&lt;br&gt;
If the connection is established via HTTPS, SSE traffic is protected by encryption.&lt;br&gt;
Browser support: &lt;a href="https://caniuse.com/eventsource" rel="noopener noreferrer"&gt;https://caniuse.com/eventsource&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this paper, we will develop a Todo List application that allows users to add, delete, mark as completed tasks in a list.&lt;/p&gt;

&lt;p&gt;Note, the state of the list using Server-sent Events will be shared by all users:&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Manifest Web Performance: Balancing JavaScript, Rendering Techniques, and Hardware Considerations</title>
      <dc:creator>Viktor Shcheglov</dc:creator>
      <pubDate>Sun, 12 May 2024 16:15:19 +0000</pubDate>
      <link>https://forem.com/shcheglov/manifest-web-performance-balancing-javascript-rendering-techniques-and-hardware-considerations-4bn8</link>
      <guid>https://forem.com/shcheglov/manifest-web-performance-balancing-javascript-rendering-techniques-and-hardware-considerations-4bn8</guid>
      <description>&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Creating an interactive web interface often involves sending a large amount of JavaScript code to users, which affects performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It's important to balance the use of JavaScript to ensure fast loading while maintaining high quality user interactions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There is a trend towards "zero JavaScript use", emphasizing reliance on default browser capabilities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Various rendering models have emerged, such as server-side rendering (SSR), island architecture, and partial hydration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SSR generates the full HTML code on the server, eliminating the need to send JavaScript to the client, but this can delay the interactivity of single-page applications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Progressive hydration selectively loads and displays components to enhance performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Optimizing JavaScript bundles can increase loading speed, reduce memory usage, and lower CPU costs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The runtime performance of JavaScript is critical, but the costs of syntactic parsing and compilation are less important.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It's important to consider hardware optimization, CPU performance, thermal regulation, cache size, and energy consumption constraints on various devices.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Network latency and bandwidth also affect website performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Understanding the real cost of JavaScript and optimizing for hardware and network conditions can significantly enhance website performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The cumulative effect of frameworks, libraries, UI components, third-party code, trackers, and analytics, known as the "JavaScript utility tax", can significantly impact performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The goal is to provide users with a fast, interactive interface as quickly as possible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Strategies for enhancing web application performance include dynamic component imports, bundle splitting, route-based and component-based code splitting, and import-on-view.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Various approaches to rendering and hydration include island architecture, progressive hydration, renewable hydration, server components in React, server-side streaming rendering, and selective hydration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I emphasized the importance of performance budgets and testing on real devices.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I recommend a free book on performance patterns available at patterns.dev.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>javascript</category>
      <category>performance</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Frontend Fundamentals: Top 10 Interview Questions and In-Depth Answers for Every Developer</title>
      <dc:creator>Viktor Shcheglov</dc:creator>
      <pubDate>Fri, 12 Apr 2024 17:02:53 +0000</pubDate>
      <link>https://forem.com/shcheglov/top-questions-3p9p</link>
      <guid>https://forem.com/shcheglov/top-questions-3p9p</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Coding Interview Questions&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;These are some questions that can be asked in coding interviews to assess a developer's skill level and ability to solve practical problems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Preventing Concurrent Editing of Articles&lt;/strong&gt;&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Suppose you are implementing a journal editing system where editors can edit articles in the admin panel. How would you prevent two editors from simultaneously editing the same article and overwriting each other's changes?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  Answer
  &lt;p&gt;Use optimistic locking or pessimistic locking mechanisms to ensure that only one editor can modify an article at a time.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Principles of Zero Downtime Deployment&lt;/strong&gt;&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;What are the principles of zero downtime deployment, an approach that deploys an application without service downtime? How is this achieved?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  Answer
  &lt;p&gt;Key principles of zero downtime deployment include:&lt;/p&gt;

&lt;p&gt;Blue-green deployment: Use two identical production environments, swapping between them during deployment.&lt;br&gt;
Feature flagging: Gradually roll out new features by controlling their visibility with feature flags.&lt;br&gt;
Canary releasing: Deploy new code to a small subset of users first, monitoring for issues before wider rollout.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Criticisms of Your Preferred Framework&lt;/strong&gt;&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Name aspects of your preferred framework that you dislike or that don't work the way you'd like. Explain how and where these issues arise and how they could be improved.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  Answer
  &lt;br&gt;
Be honest about the limitations of your chosen framework, providing specific examples and suggestions for improvement.



&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Handling Long-Running Cron Jobs&lt;/strong&gt;&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;What could happen if your cron job, which runs every minute, starts taking more than one minute to execute? How can this be prevented?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  Answer
  &lt;br&gt;
Potential issues include missed executions and cascading failures. Consider breaking down the task into smaller chunks, optimizing code, or using a queueing system.&lt;br&gt;


&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Denormalizing Data in Databases&lt;/strong&gt;&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Have you ever encountered the need to denormalize data in a database? If so, what problem were you trying to solve, what challenges did you face, and how could it have been done better?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  Answer
  &lt;p&gt;Explain the specific situation where denormalization was necessary, the trade-offs involved, and potential alternatives.&lt;/p&gt;



&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Mocking External Calls in Tests&lt;/strong&gt;&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;If you write tests, how do you circumvent the issue of external calls made by the code you're testing? Consider the scenario where external calls are prohibited on CI (continuous integration). Why is this a good practice?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  Answer
  &lt;br&gt;
Discuss techniques like mocking, stubbing, and dependency injection to isolate tests from external dependencies. Explain the benefits of avoiding external calls in CI environments.



&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Synchronizing Email Changes with External Systems&lt;/strong&gt;&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Suppose your system implements email change functionality. However, the email is also stored in an external system, such as a payment processor, which sends emails to users (but users don't directly interact with it). How would you implement email synchronization with the external system?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  Answer
  &lt;p&gt;Outline a strategy for synchronizing email changes, considering options like polling, webhooks, or message queues.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Discovering Production Errors&lt;/strong&gt;&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;How do you learn about errors that occur in production? Do you rely on user reports or have automated mechanisms in place?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  Answer
  &lt;p&gt;Describe your approach to error monitoring and reporting, emphasizing the use of tools and techniques for proactive error detection and alerting.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Designing a Simple Chat Application&lt;/strong&gt;&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;How would you design a simple chat application? You can ask the backend engineer about the backend part and the frontend engineer about the frontend part. There could be many branches in this conversation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  Answer
  &lt;br&gt;
Break down the chat application into its components (backend, frontend, database) and explain the interaction and data flow between them.&lt;br&gt;


&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. Isolating Tests in a Multi-User Environment&lt;/strong&gt;&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;How is test isolation ensured when multiple tests run concurrently and access the database, potentially modifying it? If your framework doesn't provide isolation, how would you implement or improve it?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  Answer
  &lt;br&gt;
Discuss mechanisms like transactions, rollbacks, or test databases to ensure data integrity and prevent conflicts during concurrent test execution.&lt;br&gt;


&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Additional Tips:&lt;/strong&gt;&lt;br&gt;
Encourage the candidate to elaborate on their thought process and reasoning behind their answers.&lt;br&gt;
Assess their problem-solving skills, ability to think critically, and knowledge of relevant technologies.&lt;br&gt;
Gauge their communication and collaboration skills throughout the interview.&lt;/p&gt;

</description>
      <category>coding</category>
      <category>questions</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Resume Best Practices 2024 for Standing Out in the Job Market</title>
      <dc:creator>Viktor Shcheglov</dc:creator>
      <pubDate>Thu, 14 Mar 2024 09:58:48 +0000</pubDate>
      <link>https://forem.com/shcheglov/how-to-create-a-2d-game-using-react-native-skia-3c8d</link>
      <guid>https://forem.com/shcheglov/how-to-create-a-2d-game-using-react-native-skia-3c8d</guid>
      <description>&lt;p&gt;Delete these from your CV.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Marital status&lt;/li&gt;
&lt;li&gt;Your high school and primary details if you have attended college (If you are an experienced candidate).&lt;/li&gt;
&lt;li&gt;Your Religion.&lt;/li&gt;
&lt;li&gt;Your hobbies. Nobody is going to shortlist your CV because you love traveling (unless it is a travel agent job).&lt;/li&gt;
&lt;li&gt;Non-professional email addresses. Ensure that your email address is professional and appropriate for job applications.&lt;/li&gt;
&lt;li&gt;Long paragraphs. Instead use bullet points to present information in a clear and concise manner.&lt;/li&gt;
&lt;li&gt;Irrelevant work experience.
Copy&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>Implementing a "Defer" Class in TypeScript</title>
      <dc:creator>Viktor Shcheglov</dc:creator>
      <pubDate>Tue, 05 Mar 2024 07:35:35 +0000</pubDate>
      <link>https://forem.com/shcheglov/implementing-a-defer-class-in-typescript-3ok3</link>
      <guid>https://forem.com/shcheglov/implementing-a-defer-class-in-typescript-3ok3</guid>
      <description>&lt;p&gt;When working with asynchronous operations in JavaScript and TypeScript, Promises are the heart and soul of managing those operations. However, there are cases where the traditional promise patterns such as &lt;code&gt;.then()&lt;/code&gt; and &lt;code&gt;async/await&lt;/code&gt; might not give you the level of control you require. In such cases, having a Defer class can provide a more flexible way to handle promises.&lt;/p&gt;

&lt;p&gt;In this article, we'll explore how to implement a Defer class in TypeScript, which allows for manually controlling the resolution and rejection of a promise.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Defer?
&lt;/h2&gt;

&lt;p&gt;In some programming contexts, a "defer" refers to a construct used to put off an operation until later. In the realm of promises, a Defer class can be used to create a promise whose resolution or rejection can be controlled externally, giving the programmer greater control over asynchronous flows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Defer in TypeScript
&lt;/h2&gt;

&lt;p&gt;Let's dive into how we can implement such a class in TypeScript:&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;class&lt;/span&gt; &lt;span class="nc"&gt;Defer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;promise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;PromiseLike&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;promise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;reject&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;In this implementation, &lt;code&gt;Defer&amp;lt;T&amp;gt;&lt;/code&gt; is a generic class where T represents the type of value the promise will resolve with. The constructor of this class creates a new promise, storing the &lt;code&gt;resolve&lt;/code&gt; and &lt;code&gt;reject&lt;/code&gt; functions as class properties. This allows you to invoke these functions outside the initial promise constructor context, thereby controlling the promise's outcome manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;Here is how you could use the &lt;strong&gt;Defer&lt;/strong&gt; class:&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;const&lt;/span&gt; &lt;span class="nx"&gt;myDefer&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;Defer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&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="nx"&gt;myDefer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&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;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="s2"&gt;`Resolved value: &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="c1"&gt;// Somewhere else in the code&lt;/span&gt;
&lt;span class="nx"&gt;myDefer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Outputs: Resolved value: 42&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we create an instance of &lt;code&gt;Defer&amp;lt;number&amp;gt;&lt;/code&gt;, meaning our promise will resolve with a number. We then add a &lt;code&gt;.then()&lt;/code&gt; method to handle the resolution case. Since resolve and reject are controlled externally, we can call &lt;code&gt;myDefer.resolve(42)&lt;/code&gt; anywhere in our code to resolve the promise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use a Defer?
&lt;/h2&gt;

&lt;p&gt;While it's not common to need a Defer in everyday coding with promises, there are specific scenarios where it can be invaluable:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Complex asynchronous control flow:&lt;/strong&gt; When dealing with multiple asynchronous sources that need to be synchronized in unconventional ways.&lt;br&gt;
&lt;strong&gt;Testing and Mocking: **When testing, you might want to resolve or reject promises at specific times to simulate different scenarios.&lt;br&gt;
**Advanced Resource Management:&lt;/strong&gt; In cases where resources need to be initialized asynchronously and controlled explicitly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;While the need for a &lt;strong&gt;Defer&lt;/strong&gt; class is not everyday, its availability can simplify complex asynchronous handling scenarios, making code cleaner and more understandable. Remember, with great power comes great responsibility: use it wisely and sparingly.&lt;/p&gt;

&lt;p&gt;I hope this guide helps you understand how and when to implement a Defer class in your TypeScript projects. Happy coding!&lt;/p&gt;

&lt;h2&gt;
  
  
  Discover Defer in Practice
&lt;/h2&gt;

&lt;p&gt;Interested in seeing Defer in real-world scenarios?&lt;/p&gt;

&lt;p&gt;Video Walkthrough: Dive into a live demonstration where I showcase the Defer class's applications. &lt;a href="https://www.youtube.com/watch?v=Gco9RBubWU8"&gt;https://www.youtube.com/watch?v=Gco9RBubWU8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In-depth Article: Prefer reading? Explore a detailed guide that expands on Defer's usage and benefits. &lt;a href="https://dev.to/shcheglov/make-dialog-component-like-a-hero-24e3"&gt;https://dev.to/shcheglov/make-dialog-component-like-a-hero-24e3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enhance your async handling skills with these resources!&lt;/p&gt;

&lt;p&gt;links: &lt;a href="https://github.com/shogogg/ts-deferred"&gt;https://github.com/shogogg/ts-deferred&lt;/a&gt;&lt;/p&gt;

</description>
      <category>defer</category>
      <category>react</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Memory leak detection in modern frontend app</title>
      <dc:creator>Viktor Shcheglov</dc:creator>
      <pubDate>Sun, 28 Jan 2024 11:32:58 +0000</pubDate>
      <link>https://forem.com/shcheglov/graphql-non-standard-way-of-selecting-a-client-library-5bid</link>
      <guid>https://forem.com/shcheglov/graphql-non-standard-way-of-selecting-a-client-library-5bid</guid>
      <description>&lt;p&gt;One of the challenges when building a single-page application (SPA) like dev.to or an app where users have standart session more than &lt;strong&gt;10 minutes&lt;/strong&gt;, is testing for memory leaks at a large scale. Manual testing, finding and analyzing memory leaks can be time-consuming and inefficient, especially when there are a large number of changes being made continuously by a large team of developers.&lt;/p&gt;

&lt;p&gt;This article demonstrate how to detect and automatically detect memory leaks in large applications, and how to avoid memory issues for a long period of time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Catching users experiencing problems
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Hi, dear developers. I've encountered a problem with freezing. Could you help me?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;How does it happen that some users complain about everything freezing and slowing down, while everything works fine on our expensive and beautiful Macs?&lt;/p&gt;

&lt;p&gt;The issue is that it can be challenging to replicate the problem without having access to the specific devices that your users log in from, and due to privacy settings, we may not be able to recreate the exact environment that the user experiencing the issue is in.&lt;/p&gt;

&lt;p&gt;Fortunately, browsers provide us with technical data about devices and how much memory your site consumes or allocates for certain actions. There is an API for this information, which is called the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Performance/memory"&gt;"Performance: memory"&lt;/a&gt; property.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; To write a small script that checks the performance of the system from time to time. If it detects that memory usage has exceeded a certain threshold, it can indicate that the user may be experiencing issues with RAM or a memory leak. In such a case, it is best to send all relevant technical metrics to assist in diagnosing and fixing the problem. Here is a small example:&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;// Memory usage threshold (e.g. 80% of jsHeapSizeLimit)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;threshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;jsHeapSizeLimit&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt; 

&lt;span class="c1"&gt;// Function for checking and sending memory data&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;checkMemoryUsage&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Performance.memory API is not available.&lt;/span&gt;&lt;span class="dl"&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;}&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;usedJSHeapSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jsHeapSizeLimit&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memory&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="s2"&gt;`Current memory usage: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;usedJSHeapSize&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; of &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;jsHeapSizeLimit&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;usedJSHeapSize&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;sendEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Memory usage exceeded: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;usedJSHeapSize&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; exceeds threshold of &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;threshold&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="nf"&gt;sendSnapshot&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;os&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="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;checkMemoryUsage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10000&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;NOTE: Please note that this API is not supported in all browsers and&lt;br&gt;
has recently been marked as deprecated. Sounds like that replaced by &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Performance/measureUserAgentSpecificMemory"&gt;measureUserAgentSpecificMemory&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here we send the &lt;strong&gt;userAgent, device as data&lt;/strong&gt; (there may be a problem with the device itself), and of course i would recomend also send specific for you date as example:  size of the store, number of DOM nodes and etc...&lt;/p&gt;

&lt;h2&gt;
  
  
  Catching on a  dev stage with MemLab
&lt;/h2&gt;

&lt;p&gt;We have figured out how to perfectly catch problems from real users, but this approach seems rather rash and dangerous for a large-scale enterprise project. It would be nice if our development team could highlight possible problems at the assembly or testing stages.&lt;/p&gt;

&lt;p&gt;Fortunately, Facebook has a separate team that deals with performance and quality issues. So, they developed a special tool for detecting problems at the development stage and made it available as open-source - &lt;a href="https://github.com/facebook/memlab"&gt;MemLab&lt;/a&gt;. Now, I'll talk more about it.&lt;/p&gt;

&lt;h3&gt;
  
  
  How it works
&lt;/h3&gt;

&lt;p&gt;In short, Memlab finds memory leaks by running an offline browser according to predefined test scenarios, as well as by comparing and analyzing snapshots of the JavaScript heap.&lt;br&gt;
This process takes place in six stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Browser interaction&lt;/li&gt;
&lt;li&gt;Diffing the heap&lt;/li&gt;
&lt;li&gt;Refining the list of memory leaks&lt;/li&gt;
&lt;li&gt;Clustering retainer traces&lt;/li&gt;
&lt;li&gt;Reporting the leaks&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;You can read about all these steps in detail in the &lt;a href="https://facebook.github.io/memlab/"&gt;official documentation.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Simply put, MemLab takes a snapshot of all the metrics every time and compares them to the standard, as shown in the image below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i-HwX36u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://engineering.fb.com/wp-content/uploads/2022/08/Figure-1-TEST.gif%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i-HwX36u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://engineering.fb.com/wp-content/uploads/2022/08/Figure-1-TEST.gif%3Fw%3D1024" alt="enter image description here" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, it generates a detailed report on all possible new problems, with detailed information about what was changed and how:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3rFtJ8EL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://engineering.fb.com/wp-content/uploads/2022/08/MemLab-image-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3rFtJ8EL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://engineering.fb.com/wp-content/uploads/2022/08/MemLab-image-2.png" alt="MemLab-image-2.png (1999×972)" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I would consider the disadvantages that this tool requires very careful configuration and description of all possible scenarios and screens, while if you believe the Facebook presentation, they were able to halve memory consumption and almost get rid of performance problems (&lt;strong&gt;crashes&lt;/strong&gt;)&lt;/p&gt;

&lt;p&gt;And this tool also allowed us to find a leak even in react.js&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So, nowadays, we should still not forget about the &lt;strong&gt;cost of JavaScript&lt;/strong&gt; and identifying performance issues. These can mean a lot and significantly affect a company's profits or costs.&lt;/p&gt;

&lt;p&gt;So, for example, I once worked to speed up the customer support chat for a popular European bank. The average session time for agents was &lt;strong&gt;5-6 hours&lt;/strong&gt; without restarts, but due to lag in the interface, the average user response time was around &lt;strong&gt;140 seconds&lt;/strong&gt;. After implementing two tools and fixing problems identified, both support agents and users were incredibly happy, as response time had dropped by almost half to &lt;strong&gt;80 seconds.&lt;/strong&gt; Agents themselves told me that it was nice when everything worked smoothly and quickly (I think this was because their salary depended on it too, haha).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good luck and speed to your projects, and no MEMORY LEAKS anymore!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>performance</category>
    </item>
    <item>
      <title>Mastering Modal Dialogs in React Like a Pro</title>
      <dc:creator>Viktor Shcheglov</dc:creator>
      <pubDate>Thu, 25 Jan 2024 10:29:34 +0000</pubDate>
      <link>https://forem.com/shcheglov/make-dialog-component-like-a-hero-24e3</link>
      <guid>https://forem.com/shcheglov/make-dialog-component-like-a-hero-24e3</guid>
      <description>&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%2Fnjwbs2nkkq6wivb4xclf.png" 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%2Fnjwbs2nkkq6wivb4xclf.png" alt="Image description" width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Modals, dialogs, popups, snackbars, notification, alert, confirm and etc…&lt;/p&gt;

&lt;p&gt;It's hard to imagine modern React Application without pop-up dialogs for confirming addresses, deleting items from a cart, and other such interactions — challenges every developer faces daily.&lt;/p&gt;

&lt;p&gt;The design and management architecture of these dialogs often raise numerous questions. I've encountered everything from complex integration schemes with stores to extensive prop drilling for opening windows, and intricate setups using event emitters. It's time to tackle these issues head-on.&lt;/p&gt;

&lt;p&gt;In this article, I'll share the solution our team has developed, which significantly aids us in maintaining clean code daily, even as our project scales.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;Let's take a look at this typical example of how developers usually display modals:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;№1: Boilerplate&lt;/strong&gt;&lt;br&gt;
Managing dialog in app often involves creating several state variables to control their opening and closing. A typical setup for a component might start with several lines of code like this:&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;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;openConfirm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setOpenConfirm&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="kc"&gt;false&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;deleteDialogOpened&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setDeleteDialog&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="kc"&gt;false&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;editDialogOpened&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEditDialog&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="kc"&gt;false&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;moveOnDialogOpened&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setMoveOnDialog&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="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Does this code look familiar?&lt;/p&gt;

&lt;p&gt;Can you imagine the complexity involved in rendering this component, where hundreds of lines of code in JSX track how and when these dialogs open? Managing several dialog windows in this way not only clutters the components but also increases the risk of bugs, as the state of each dialog is intertwined with the overall logic of the component.&lt;/p&gt;

&lt;p&gt;№2: Performance&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%2Fsbeq71znr6co3u6evq5c.png" 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%2Fsbeq71znr6co3u6evq5c.png" alt="Image description" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine you have a table where every cell has its own set of dialog boxes for management tasks. If you put the dialog control logic right inside each cell's component, React ends up doing a lot of work. For every update, it has to check through hundreds of these virtual parts to figure out which dialog boxes to show or hide. This can slow things down because React has to keep comparing all these parts every time something changes. It makes your code more complex and harder to deal with, too.&lt;/p&gt;

&lt;p&gt;Moving dialogs to a parent level seems straightforward, but the main issue was this:prop drilling. Ultimately, you end up having to pass data through many layers to reach the dialog windows, which complicates matters. It's like unraveling a knot that only gets tighter the more you pull on it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;№3: Package size&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In large projects with numerous dialogs, a problem arises: many dialogs are loaded but never used by some users. Without code splitting, other forms of preloading/caching, or similar strategies, the application can become sluggish, loading unnecessary items.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;We often see two main types of dialogs in apps. First, there are the common ones, used about 90% of the time, like confirmation messages, map location pickers, ads, or subscription offers.&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%2Frsavy663cf0mr9uk7a9j.png" 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%2Frsavy663cf0mr9uk7a9j.png" alt="Image description" width="800" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These dialogs pop up frequently, look similar, and aren't tied to any specific part of the app. Then, there's the other 10%: specialized dialogs made for one-time events or specific actions. By figuring out which dialogs are used most and which are for special occasions, we can make managing and loading them much easier.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution — Modal Manager
&lt;/h3&gt;

&lt;p&gt;💡 My idea is to create a single entry point for all dialogs, allowing us to manage them as conveniently as we do routes in React applications. This means we will describe their behavior strategy, share data, and invoke them using hooks and React context. By leveraging Suspense, we can ensure that these dialogs are not loaded unnecessarily. This approach streamlines dialog management, making it more efficient and less prone to performance issues. By centralizing dialog control, we can easily adjust their behavior and appearance across the entire application, improving consistency and user experience. Additionally, using Suspense for lazy loading helps keep our app lightweight, loading resources only when they are truly needed.&lt;/p&gt;

&lt;p&gt;Let’s do it:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;lazy&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="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;Modals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ConfirmModal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;SubscriptionModal&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DialogManager&lt;/span&gt; &lt;span class="o"&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;Modals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConfirmModal&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nf"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./modals/ConfirmModal&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;Modals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SubscriptionModal&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nf"&gt;lazy&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="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@components/common/Subscriptions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;DialogManager&lt;/code&gt; - just a simple hashmap, where each dialog is associated with a unique key and contain a lazy component of the dialog.&lt;/p&gt;

&lt;h3&gt;
  
  
  Provider
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DialogStructure&lt;/span&gt; &lt;span class="o"&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="nx"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;component&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="nx"&gt;JSX&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Element&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DialogCloseHandler&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;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;onCloseHandler&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;T&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;T&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;useDialogProvider&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;activeDialogs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setActiveDialogs&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DialogStructure&lt;/span&gt;&lt;span class="o"&gt;&amp;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;close&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&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="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;unknown&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="nf"&gt;setActiveDialogs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;activeDialogs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dialog&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;id&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;value&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;activeDialogs&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;open&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&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;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Modals&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Omit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ComponentProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;dialogManager&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="nx"&gt;T&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;onCloseHandler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;nanoid&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;Component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dialogManager&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Modals&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

      &lt;span class="nf"&gt;setActiveDialogs&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;component&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onCloseHandler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;activeDialogs&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="kc"&gt;null&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;activeDialogs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;close&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="nf"&gt;useMemo&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="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;close&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;activeDialogs&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;close&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;activeDialogs&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DialogContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
  &lt;span class="nx"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;useDialogProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break down our magic in more detail:&lt;/p&gt;

&lt;p&gt;Let's delve deeper into our methodology:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the &lt;code&gt;activeDialogs&lt;/code&gt; state, we accumulate our dialogs. This is an array because we anticipate that multiple dialogs might be called one after another.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;useDialogProvider&lt;/code&gt; is what's passed as a value to our &lt;code&gt;DialogContext&lt;/code&gt;. It's crucial that it returns both an opening function and a closing function, as well as a list of all dialogs.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;open&lt;/code&gt; function is generic, thanks to , it knows the props our dialog accepts. This will be incredibly useful for invoking our dialogs in the future.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;close&lt;/code&gt; - simply deletes our component from activeDialogs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onCloseHandler&lt;/code&gt; is one of the key tricks of our architecture. The only thing our manager-created dialog needs to know is how to close itself. There are numerous ways to teach it this, but the simplest method seems to be incorporating a &lt;code&gt;callback&lt;/code&gt; into each of the dialogs invoked by our system that can perform this action.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Context and  part
&lt;/h3&gt;

&lt;p&gt;Now, let's focus on our context setup:&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DialogProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PropsWithChildren&lt;/span&gt;&lt;span class="o"&gt;&amp;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;children&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;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useDialogProvider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DialogContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;activeDialogs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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;lt;&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&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;gt;&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;activeDialogs&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;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LazyDialog&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LazyDialog&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="p"&gt;))}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Suspense&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;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="sr"&gt;/DialogContext.Provider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember how we opted for &lt;code&gt;lazy&lt;/code&gt; wrapping for our dialogs within the manager to facilitate on-demand loading? By incorporating &lt;code&gt;Suspense&lt;/code&gt; in our provider, we streamline this process even further. Now, iterating through any open dialogs in our provider becomes straightforward, ensuring that dialogs are loaded efficiently and only when necessary, enhancing the overall performance and user experience of our application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hook useDialog
&lt;/h3&gt;

&lt;p&gt;This is the final piece of our entire splendid structure. Now, we need to learn how to conveniently invoke our dialogs from anywhere within our application. I suggest doing this with the useDialog hook, as all the necessary functionality for it is already in place:&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useDialog&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;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DialogContext&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;context&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;useDialog() called outside of DialogProvider&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Now, in any component, we can simply call:&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;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useDialog&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;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;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Modals&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;onConfirm&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="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reload&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="nx"&gt;Buy&lt;/span&gt; &lt;span class="nx"&gt;subscription&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After we use Modals.Subscription, our TS and IDE will help us correctly identify the missing props. Therefore, we've added an onConfirm callback because that's what our subscription dialog component requires.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final
&lt;/h3&gt;

&lt;p&gt;In essence, this is what we've achieved:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A Clearly Defined Dialog Structure&lt;/strong&gt;: All popular or frequently used popups are extracted and described in a special manager. If you prefer not to use this approach for some dialogs, you can still do it the old way, and everything will work just fine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asynchronous Code:&lt;/strong&gt; We load our code as needed using lazy loading and Suspense, making our application lighter and faster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No More Boilerplate:&lt;/strong&gt; Managing the state of our dialogs is now encapsulated within the &lt;code&gt;useDialog&lt;/code&gt; hook and can be expanded according to the needs of your application.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With these improvements, our application benefits from a more organized, efficient, and scalable dialog management system. This structure not only enhances performance but also simplifies development and maintenance, providing a clear path forward for incorporating dialog windows in a React application.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>dialogs</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>useRequest: Create a Basic Declarative React hook for Managing API Requests as an Alternative to useQuery</title>
      <dc:creator>Viktor Shcheglov</dc:creator>
      <pubDate>Sat, 20 Jan 2024 09:15:24 +0000</pubDate>
      <link>https://forem.com/shcheglov/userequest-create-a-basic-declarative-react-hook-for-managing-api-requests-as-an-alternative-to-usequery-28ci</link>
      <guid>https://forem.com/shcheglov/userequest-create-a-basic-declarative-react-hook-for-managing-api-requests-as-an-alternative-to-usequery-28ci</guid>
      <description>&lt;p&gt;In the world of React, managing API requests and their state can be a complex task. Libraries like &lt;strong&gt;react-query&lt;/strong&gt; have provided robust solutions, but sometimes, you might need something simpler and more controllable. This is where a custom hook, &lt;strong&gt;useRequest&lt;/strong&gt;, comes into play. This article will guide you through creating &lt;strong&gt;useRequest&lt;/strong&gt; - a straightforward, declarative hook for handling API requests without the advanced features of &lt;strong&gt;react-query&lt;/strong&gt;, making it a lighter and more straightforward alternative.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is useRequest?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;useRequest&lt;/strong&gt; is a custom React hook designed to fetch data from an API and manage its state within a component. It's built using React's basic hooks - &lt;em&gt;useState, useEffect&lt;/em&gt;, and &lt;em&gt;useCallback&lt;/em&gt;. The goal is to provide a simple way to make API requests, track loading states, handle errors, and cache responses with minimal setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why useRequest?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While react-query is powerful, it can be overkill for simple projects or when you need more direct control over request handling. useRequest:&lt;/p&gt;

&lt;p&gt;Simplifies state management for API requests.&lt;br&gt;
Provides built-in loading and error states.&lt;br&gt;
Offers basic caching capabilities.&lt;br&gt;
Is easy to integrate and use in small to medium-sized projects.&lt;br&gt;
Building the useRequest Hook:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Setup and State Management:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Start by setting up the hook structure using useState to manage the data, error, and loading states.&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;const&lt;/span&gt; &lt;span class="nx"&gt;useRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queryFn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;queryKey&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="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;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&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="kc"&gt;null&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;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setError&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="kc"&gt;null&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;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsLoading&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="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Rest of the logic will go here&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Fetching Data:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use useEffect and useCallback to fetch data from the API. useCallback ensures that the function doesn't get recreated unless necessary.&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;const&lt;/span&gt; &lt;span class="nx"&gt;fetchData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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="nf"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;try&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;queryFn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setIsLoading&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="p"&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;queryFn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;queryKey&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="nf"&gt;fetchData&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="nx"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Caching Mechanism:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Implement a basic caching mechanism to store and retrieve responses using a global object.&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;const&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="c1"&gt;// Inside fetchData&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;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;queryKey&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;}&lt;/span&gt;
&lt;span class="c1"&gt;// Save to cache after fetching&lt;/span&gt;
&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Adding Cache Control:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Provide functions to clear specific cache entries or the entire cache.&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;const&lt;/span&gt; &lt;span class="nx"&gt;clearCache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&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="cm"&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;queryKey&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;clearAllCache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&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="cm"&gt;/*...*/&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. Return from the Hook:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finally, return the data, loading state, error, and cache control functions from the hook.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Usage Example: *&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Demonstrate how to use useRequest in a component, including fetching data, displaying it, and handling loading and error states.&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;const&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&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;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;refetch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fetchMyData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myData&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Render your component based on the data, loading, and error states&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Bonus: Adding Type Safety to useRequest with TypeScript&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For developers using TypeScript, adding type safety to your useRequest hook enhances its reliability and the overall developer experience. TypeScript's generics allow you to define the type of data your API request will return, ensuring type correctness throughout your component.&lt;/p&gt;

&lt;p&gt;To add type safety to useRequest, modify the hook to accept a generic type parameter. This parameter will represent the type of data expected from the API:&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;const&lt;/span&gt; &lt;span class="nx"&gt;useRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;queryFn&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;queryKey&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;UseRequestReturn&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;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;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&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;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setError&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&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;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsLoading&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="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// ... rest of the hook implementation&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Define a return type for the hook that includes the generic type T:&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="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UseRequestReturn&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;refetch&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="k"&gt;void&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;Now, when you use the useRequest hook in your components, you can specify the type of data you expect.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;useRequest&lt;/strong&gt; provides a simpler, more direct way to handle API requests in React applications. While it doesn't offer the advanced features of react-query, it's an excellent tool for developers who need a lightweight and straightforward approach to managing API states. This custom hook can be a valuable addition to your React toolkit, especially in projects where simplicity and direct control are paramount.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Encourage readers to try implementing &lt;strong&gt;useRequest&lt;/strong&gt; in their projects, and suggest experimenting with additional features like request deduplication or more advanced caching mechanisms to further enhance the hook's capabilities.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
