{"@attributes":{"version":"2.0"},"channel":{"title":"DEV Community: Sam Magura","description":"The latest articles on DEV Community by Sam Magura (@srmagura).","link":"https:\/\/dev.to\/srmagura","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%2F710804%2F8be2ddc2-d75f-47fc-a72c-ff8242808815.jpg","title":"DEV Community: Sam Magura","link":"https:\/\/dev.to\/srmagura"},"language":"en","item":[{"title":"Why We're Breaking Up with CSS-in-JS","pubDate":"Sun, 16 Oct 2022 19:52:59 +0000","link":"https:\/\/dev.to\/srmagura\/why-were-breaking-up-wiht-css-in-js-4g9b","guid":"https:\/\/dev.to\/srmagura\/why-were-breaking-up-wiht-css-in-js-4g9b","description":"<p>Hi, I'm Sam \u2014 software engineer at <a href=\"https:\/\/www.spotvirtual.com\/\" rel=\"noopener noreferrer\">Spot<\/a> and the 2nd most active maintainer of <a href=\"https:\/\/emotion.sh\/\" rel=\"noopener noreferrer\">Emotion<\/a>, a widely-popular CSS-in-JS library for React. This post will delve into what originally attracted me to CSS-in-JS, and why I (along with the rest of the Spot team) have decided to shift away from it.<\/p>\n\n<p>We'll start with an overview of CSS-in-JS and give an overview of its pros &amp; cons. Then, we'll do a deep dive into the performance issues that CSS-in-JS caused at Spot and how you can avoid them.<\/p>\n\n<h2>\n  \n  \n  What is CSS-in-JS?\n<\/h2>\n\n<p>As the name suggests, CSS-in-JS allows you to style your React components by writing CSS directly in your JavaScript or TypeScript code:<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight tsx\"><code>\n\n<span class=\"c1\">\/\/ @emotion\/react (css prop), with object styles<\/span>\n<span class=\"kd\">function<\/span> <span class=\"nf\">ErrorMessage<\/span><span class=\"p\">({<\/span> <span class=\"nx\">children<\/span> <span class=\"p\">})<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">return <\/span><span class=\"p\">(<\/span>\n    <span class=\"p\">&lt;<\/span><span class=\"nt\">div<\/span>\n      <span class=\"na\">css<\/span><span class=\"p\">=<\/span><span class=\"si\">{<\/span><span class=\"p\">{<\/span>\n        <span class=\"na\">color<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">red<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"na\">fontWeight<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">bold<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n      <span class=\"p\">}<\/span><span class=\"si\">}<\/span>\n    <span class=\"p\">&gt;<\/span>\n      <span class=\"si\">{<\/span><span class=\"nx\">children<\/span><span class=\"si\">}<\/span>\n    <span class=\"p\">&lt;\/<\/span><span class=\"nt\">div<\/span><span class=\"p\">&gt;<\/span>\n  <span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"c1\">\/\/ styled-components or @emotion\/styled, with string styles<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">ErrorMessage<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">styled<\/span><span class=\"p\">.<\/span><span class=\"nx\">div<\/span><span class=\"s2\">`\n  color: red;\n  font-weight: bold;\n`<\/span><span class=\"p\">;<\/span>\n\n\n<\/code><\/pre>\n\n<\/div>\n\n<p><a href=\"https:\/\/styled-components.com\/\" rel=\"noopener noreferrer\">styled-components<\/a> and <a href=\"https:\/\/emotion.sh\/\" rel=\"noopener noreferrer\">Emotion<\/a> are the most popular CSS-in-JS libraries in the React community. While I have only used Emotion, I believe virtually all points in this article apply to styled-components as well.<\/p>\n\n<p>This article focuses on <strong>runtime CSS-in-JS<\/strong>, a category which includes both styled-components and Emotion. Runtime CSS-in-JS simply means that the library interprets and applies your styles when the application runs. We'll briefly discuss compile-time CSS-in-JS at the end of the article.<\/p>\n\n<h2>\n  \n  \n  The Good, The Bad, and the Ugly of CSS-in-JS\n<\/h2>\n\n<p>Before we get into the nitty-gritty of specific CSS-in-JS coding patterns and their implications for performance, let's start with a high-level overview of why you might choose to adopt the technology, and why you might not.<\/p>\n\n<h3>\n  \n  \n  The Good\n<\/h3>\n\n<p><strong>1. Locally-scoped styles.<\/strong> When writing plain CSS, it's very easy to accidentally apply styles more widely than you intended. For example, imagine you're making a list view where each row should have some padding and a border. You'd likely write CSS like this:<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight css\"><code>\n\n   <span class=\"nc\">.row<\/span> <span class=\"p\">{<\/span>\n     <span class=\"nl\">padding<\/span><span class=\"p\">:<\/span> <span class=\"m\">0.5rem<\/span><span class=\"p\">;<\/span>\n     <span class=\"nl\">border<\/span><span class=\"p\">:<\/span> <span class=\"m\">1px<\/span> <span class=\"nb\">solid<\/span> <span class=\"m\">#ddd<\/span><span class=\"p\">;<\/span>\n   <span class=\"p\">}<\/span>\n\n\n<\/code><\/pre>\n\n<\/div>\n\n<p>Several months later when you've completely forgotten about the list view, you create another component that has rows. Naturally, you set <code>className=\"row\"<\/code> on these elements. Now the new component's rows have an unsightly border and you have no idea why! While this type of problem can be solved by using longer class names or more specific selectors, it's still on you as the developer to ensure there are no class name conflicts.<\/p>\n\n<p>CSS-in-JS completely solves this problem by making styles locally-scoped by default. If you were to write your list view row as<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight tsx\"><code>\n\n<span class=\"p\">&lt;<\/span><span class=\"nt\">div<\/span> <span class=\"na\">css<\/span><span class=\"p\">=<\/span><span class=\"si\">{<\/span><span class=\"p\">{<\/span> <span class=\"na\">padding<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">0.5rem<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"na\">border<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">1px solid #ddd<\/span><span class=\"dl\">'<\/span> <span class=\"p\">}<\/span><span class=\"si\">}<\/span><span class=\"p\">&gt;<\/span>...<span class=\"p\">&lt;\/<\/span><span class=\"nt\">div<\/span><span class=\"p\">&gt;<\/span>\n\n\n<\/code><\/pre>\n\n<\/div>\n\n<p>there is no way the padding and border can accidentally get applied to unrelated elements.<\/p>\n\n<blockquote>\n<p>Note: CSS Modules also provide locally-scoped styles.<\/p>\n<\/blockquote>\n\n<p><strong>2. Colocation.<\/strong> If using plain CSS, you might put all of your <code>.css<\/code> files in a <code>src\/styles<\/code> directory, while all of your React components live in <code>src\/components<\/code>. As the size of the application grows, it quickly becomes difficult to tell which styles are used by each component. Often times, you will end up with dead code in your CSS because there's no easy way to tell that the styles aren't being used.<\/p>\n\n<p>A better approach for organizing your code is to <strong>include everything related to a single component in same place.<\/strong> This practice, called colocation, has been covered in an <a href=\"https:\/\/kentcdodds.com\/blog\/colocation\" rel=\"noopener noreferrer\">excellent blog post<\/a> by Kent C. Dodds.<\/p>\n\n<p>The problem is that it's hard to implement colocation when using plain CSS, since CSS and JavaScript have to go in separate files, and your styles will apply globally regardless of where the <code>.css<\/code> file is located. On the other hand, if you're using CSS-in-JS, you can write your styles directly inside the React component that uses them! If done correctly, this greatly improves the maintainability of your application.<\/p>\n\n<blockquote>\n<p>Note: CSS Modules also allow you to colocate styles with components, though not in the same file.<\/p>\n<\/blockquote>\n\n<p><strong>3. You can use JavaScript variables in styles.<\/strong> CSS-in-JS enables you to reference JavaScript variables in your style rules, e.g.:<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight tsx\"><code>\n\n<span class=\"c1\">\/\/ colors.ts<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">const<\/span> <span class=\"nx\">colors<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n  <span class=\"na\">primary<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">#0d6efd<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">border<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">#ddd<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n  <span class=\"cm\">\/* ... *\/<\/span>\n<span class=\"p\">};<\/span>\n\n<span class=\"c1\">\/\/ MyComponent.tsx<\/span>\n<span class=\"kd\">function<\/span> <span class=\"nf\">MyComponent<\/span><span class=\"p\">({<\/span> <span class=\"nx\">fontSize<\/span> <span class=\"p\">})<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">return <\/span><span class=\"p\">(<\/span>\n    <span class=\"p\">&lt;<\/span><span class=\"nt\">p<\/span>\n      <span class=\"na\">css<\/span><span class=\"p\">=<\/span><span class=\"si\">{<\/span><span class=\"p\">{<\/span>\n        <span class=\"na\">color<\/span><span class=\"p\">:<\/span> <span class=\"nx\">colors<\/span><span class=\"p\">.<\/span><span class=\"nx\">primary<\/span><span class=\"p\">,<\/span>\n        <span class=\"nx\">fontSize<\/span><span class=\"p\">,<\/span>\n        <span class=\"na\">border<\/span><span class=\"p\">:<\/span> <span class=\"s2\">`1px solid <\/span><span class=\"p\">${<\/span><span class=\"nx\">colors<\/span><span class=\"p\">.<\/span><span class=\"nx\">border<\/span><span class=\"p\">}<\/span><span class=\"s2\">`<\/span><span class=\"p\">,<\/span>\n      <span class=\"p\">}<\/span><span class=\"si\">}<\/span>\n    <span class=\"p\">&gt;<\/span>\n      ...\n    <span class=\"p\">&lt;\/<\/span><span class=\"nt\">p<\/span><span class=\"p\">&gt;<\/span>\n  <span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n\n\n<\/code><\/pre>\n\n<\/div>\n\n<p>As this example shows, you can use both JavaScript constants (e.g. <code>colors<\/code>) and React props \/ state (e.g. <code>fontSize<\/code>) in CSS-in-JS styles. The ability to use JavaScript constants in styles reduces duplication in some cases, since the same constant does not have to be defined as both a CSS variable and a JavaScript constant. The ability to use props &amp; state allows you to create components with highly-customizable styles, without using inline styles. (Inline styles are not ideal for performance when the same styles are applied to many elements.)<\/p>\n\n<h3>\n  \n  \n  The Neutral\n<\/h3>\n\n<p><strong>1. It's the hot new technology.<\/strong> Many web developers, myself included, are quick to adopt the hottest new trends in the JavaScript community. Part of this is rationale, since in many cases, new libraries and frameworks have proven to be massive improvements over their predecessors (just think about how much React enhances productivity over earlier libraries like jQuery). On the other hand, the other part of our obsession with shiny new tools is just that \u2014 an obsession. We're afraid of missing out on the next big thing, and we might overlook real drawbacks when deciding to adopt a new library or framework. I think this has certainly been a factor in the widespread adoption of CSS-in-JS \u2014 at least it was for me.<\/p>\n\n<h3>\n  \n  \n  The Bad\n<\/h3>\n\n<p><strong>1. CSS-in-JS adds runtime overhead.<\/strong> When your components render, the CSS-in-JS library must \"serialize\" your styles into plain CSS that can be inserted into the document. It's clear that this takes up extra CPU cycles, but is it enough to have a noticeable impact on the performance of your application? <strong>We'll investigate this question in depth in the next section.<\/strong><\/p>\n\n<p><strong>2. CSS-in-JS increases your bundle size.<\/strong> This is an obvious one \u2014 each user who visits your site now has to download the JavaScript for the CSS-in-JS library. Emotion is <a href=\"https:\/\/bundlephobia.com\/package\/@emotion\/react@11.10.4\" rel=\"noopener noreferrer\">7.9 kB<\/a> minzipped and styled-components is <a href=\"https:\/\/bundlephobia.com\/package\/styled-components@5.3.6\" rel=\"noopener noreferrer\">12.7 kB<\/a>. So neither library is huge, but it all adds up. (<code>react<\/code> + <code>react-dom<\/code> is 44.5 kB for comparison.)<\/p>\n\n<p><strong>3. CSS-in-JS clutters the React DevTools.<\/strong> For each element that uses the <code>css<\/code> prop, Emotion will render <code>&lt;EmotionCssPropInternal&gt;<\/code> and <code>&lt;Insertion&gt;<\/code> components. If you are using the <code>css<\/code> prop on many elements, Emotion's internal components can really clutter up the React DevTools, as seen here:<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8uh0gzxizoja69rh5ssm.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8uh0gzxizoja69rh5ssm.png\" alt=\"The React DevTools displaying many internal Emotion components\" width=\"335\" height=\"458\"><\/a><\/p>\n\n<h3>\n  \n  \n  The Ugly\n<\/h3>\n\n<p><strong>1. Frequently inserting CSS rules forces the browser to do a lot of extra work.<\/strong> <a href=\"https:\/\/github.com\/sebmarkbage\" rel=\"noopener noreferrer\">Sebastian Markb\u00e5ge<\/a>, member of the React core team and the original designer of React Hooks, wrote an <a href=\"https:\/\/github.com\/reactwg\/react-18\/discussions\/110\" rel=\"noopener noreferrer\">extremely informative discussion<\/a> in the React 18 working group about how CSS-in-JS libraries would need to change to work with React 18, and about the future of runtime CSS-in-JS in general. In particular, he says:<\/p>\n\n<blockquote>\n<p>In concurrent rendering, React can yield to the browser between renders. If you insert a new rule in a component, then React yields, the browser then have to see if those rules would apply to the existing tree. So it recalculates the style rules. Then React renders the next component, and then that component discovers a new rule and it happens again.<\/p>\n\n<p><strong>This effectively causes a recalculation of all CSS rules against all DOM nodes every frame while React is rendering.<\/strong> This is VERY slow.<\/p>\n<\/blockquote>\n\n<p><strong>Update 2022-10-25:<\/strong> This quote from Sebastian is specifically referring to performance in React Concurrent Mode, <strong>without<\/strong> <code>useInsertionEffect<\/code>. I recommend reading the full discussion if you want an in-depth understanding of this. Thanks to Dan Abramov for <a href=\"https:\/\/twitter.com\/dan_abramov\/status\/1584838817982590976\" rel=\"noopener noreferrer\">pointing out<\/a> this inaccuracy on Twitter.<\/p>\n\n<p>The worst thing about this problem is that it's not a fixable issue (within the context of runtime CSS-in-JS). Runtime CSS-in-JS libraries work by inserting new style rules when components render, and this is bad for performance on a fundamental level.<\/p>\n\n<p><strong>2. With CSS-in-JS, there's a lot more that can go wrong, especially when using SSR and\/or component libraries.<\/strong> In the Emotion GitHub repository, we receive <em>tons<\/em> of issues that go like this:<\/p>\n\n<blockquote>\n<p>I'm using Emotion with server-side rendering and MUI\/Mantine\/(another Emotion-powered component library) and it's not working because...<\/p>\n<\/blockquote>\n\n<p>While the root cause varies from issue to issue, there are some common themes:<\/p>\n\n<ul>\n<li>Multiple instances of Emotion get loaded at once. This can cause problems even if the multiple instances are all the same version of Emotion. <a href=\"https:\/\/github.com\/emotion-js\/emotion\/issues\/2639\" rel=\"noopener noreferrer\">(Example issue)<\/a>\n<\/li>\n<li>Component libraries often do not give you full control over the order in which styles are inserted. <a href=\"https:\/\/github.com\/emotion-js\/emotion\/issues\/2803\" rel=\"noopener noreferrer\">(Example issue)<\/a>\n<\/li>\n<li>Emotion's SSR support works differently between React 17 and React 18. This was necessary for compatibility with React 18's streaming SSR. <a href=\"https:\/\/github.com\/emotion-js\/emotion\/issues\/2725\" rel=\"noopener noreferrer\">(Example issue)<\/a>\n<\/li>\n<\/ul>\n\n<p>And believe me, these sources of complexity are just the tip of the iceberg. (If you're feeling brave, take a look at the <a href=\"https:\/\/github.com\/emotion-js\/emotion\/blob\/8a163746f0de5c6a43052db37f14c36d703be7b9\/packages\/styled\/types\/base.d.ts\" rel=\"noopener noreferrer\">TypeScript definitions for <code>@emotion\/styled<\/code><\/a>.)<\/p>\n\n<h2>\n  \n  \n  Performance Deep Dive\n<\/h2>\n\n<p>At this point, it's clear that there are both significant pros and significant cons to runtime CSS-in-JS. To understand why our team is moving away from the technology, we need to explore the real-world performance impact of CSS-in-JS.<\/p>\n\n<p>This section focuses on the performance impact of Emotion, <strong>as it was used in the Spot codebase.<\/strong> As such, it would be a mistake to assume that the performance numbers presented below apply to your codebase as well \u2014 there are many ways to use Emotion, and each of these has its own performance characteristics.<\/p>\n\n<h3>\n  \n  \n  Serialization Inside of Render vs. Outside of Render\n<\/h3>\n\n<p><em>Style serialization<\/em> refers to the process by which Emotion takes your CSS string or object styles and converts them to a plain CSS string that can be inserted into the document. Emotion also computes a hash of the plain CSS during serialization \u2014 this hash is what you see in the generated class names, e.g. <code>css-15nl2r3<\/code>.<\/p>\n\n<p>While I have not measured this, I believe one of the most significant factors in how Emotion performs is whether style serialization is performed inside or outside of the React render cycle.<\/p>\n\n<p>The examples in the Emotion docs perform serialization inside render, like this:<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight tsx\"><code>\n\n<span class=\"kd\">function<\/span> <span class=\"nf\">MyComponent<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">return <\/span><span class=\"p\">(<\/span>\n    <span class=\"p\">&lt;<\/span><span class=\"nt\">div<\/span>\n      <span class=\"na\">css<\/span><span class=\"p\">=<\/span><span class=\"si\">{<\/span><span class=\"p\">{<\/span>\n        <span class=\"na\">backgroundColor<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">blue<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"na\">width<\/span><span class=\"p\">:<\/span> <span class=\"mi\">100<\/span><span class=\"p\">,<\/span>\n        <span class=\"na\">height<\/span><span class=\"p\">:<\/span> <span class=\"mi\">100<\/span><span class=\"p\">,<\/span>\n      <span class=\"p\">}<\/span><span class=\"si\">}<\/span>\n    <span class=\"p\">\/&gt;<\/span>\n  <span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n\n\n<\/code><\/pre>\n\n<\/div>\n\n<p>Every time <code>MyComponent<\/code> renders, the object styles are serialized again. If <code>MyComponent<\/code> renders frequently (e.g. on every keystroke), the repeated serialization may have a high performance cost.<\/p>\n\n<p>A more performant approach is to move the styles outside of the component, so that serialization happens one time when the module loads, instead of on each render. You can do this with the <code>css<\/code> function from <code>@emotion\/react<\/code>:<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight tsx\"><code>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">myCss<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">css<\/span><span class=\"p\">({<\/span>\n  <span class=\"na\">backgroundColor<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">blue<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">width<\/span><span class=\"p\">:<\/span> <span class=\"mi\">100<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">height<\/span><span class=\"p\">:<\/span> <span class=\"mi\">100<\/span><span class=\"p\">,<\/span>\n<span class=\"p\">});<\/span>\n\n<span class=\"kd\">function<\/span> <span class=\"nf\">MyComponent<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">return<\/span> <span class=\"p\">&lt;<\/span><span class=\"nt\">div<\/span> <span class=\"na\">css<\/span><span class=\"p\">=<\/span><span class=\"si\">{<\/span><span class=\"nx\">myCss<\/span><span class=\"si\">}<\/span> <span class=\"p\">\/&gt;;<\/span>\n<span class=\"p\">}<\/span>\n\n\n<\/code><\/pre>\n\n<\/div>\n\n<p>Of course, this prevents you from accessing props in your styles, so you are missing out on one of the main selling points of CSS-in-JS.<\/p>\n\n<p><strong>At Spot, we performed style serialization in render, so the following performance analysis will focus on this case.<\/strong><\/p>\n\n<h3>\n  \n  \n  Benchmarking the Member Browser\n<\/h3>\n\n<p>It's finally time to make things concrete by profiling a real component from Spot. We'll be using the Member Browser, a fairly simple list view that shows you all of the users in your team. Virtually all of the Member Browser's styles are using Emotion, specifically the <code>css<\/code> prop.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ds504qgf3ni0mjkujyu.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ds504qgf3ni0mjkujyu.png\" alt=\"The Member Browser in Spot\" width=\"800\" height=\"283\"><\/a><\/p>\n\n<p>For the test,<\/p>\n\n<ul>\n<li>The Member Browser will display 20 users,<\/li>\n<li>The <code>React.memo<\/code> around the list items will be removed, and<\/li>\n<li>We'll force the top-most <code>&lt;BrowseMembers&gt;<\/code> component to render each second, and record the times for the first 10 renders.<\/li>\n<li>React Strict Mode is off. (It effectively doubles the render times you see in the profiler.)<\/li>\n<\/ul>\n\n<p>I profiled the page using the React DevTools and got <strong>54.3 ms<\/strong> as the average of the first 10 render times.<\/p>\n\n<p>My personal rule of thumb is that a React component should take 16 ms or less to render, since 1 frame at 60 frames per second is 16.67 ms. The Member Browser is currently over 3 times this figure, so it's a pretty heavyweight component.<\/p>\n\n<p>This test was performed on an <strong>M1 Max<\/strong> CPU which is WAY faster than what the average user will have. The 54.3 ms render time that I got could easily be <strong>200 ms<\/strong> on a less powerful machine.<\/p>\n\n<h3>\n  \n  \n  Analyzing the Flamegraph\n<\/h3>\n\n<p>Here's the flamegraph for a <strong>single list item<\/strong> from the above test:<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb8o8ubckz1qrn9753pp0.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb8o8ubckz1qrn9753pp0.png\" alt=\"Performance flamegraph of the BrowseMembersItem component\" width=\"800\" height=\"170\"><\/a><\/p>\n\n<p>As you can see, there are a huge number of <code>&lt;Box&gt;<\/code> and <code>&lt;Flex&gt;<\/code> components being rendered \u2014 these are our \"style primitives\" which use the <code>css<\/code> prop. While each <code>&lt;Box&gt;<\/code> only takes 0.1 \u2013 0.2 ms to render, this adds up because the total number of <code>&lt;Box&gt;<\/code> components is massive.<\/p>\n\n<h3>\n  \n  \n  Benchmarking the Member Browser, without Emotion\n<\/h3>\n\n<p>To see how much of this expensive render was due to Emotion, I rewrote the Member Browser styles using Sass Modules instead of Emotion. (Sass Modules are compiled to plain CSS at build time, so there is virtually no performance penalty to using them.)<\/p>\n\n<p>I repeated the same test described above and got <strong>27.7 ms<\/strong> as the average of the first 10 renders. That's a <strong>48% decrease<\/strong> from the original time!<\/p>\n\n<p>So, that's the reason we are breaking up with CSS-in-JS: the runtime performance cost is simply too high.<\/p>\n\n<p>To repeat my disclaimer from above: this result only directly applies to the Spot codebase and how we were using Emotion. If your codebase is using Emotion in a more performant way (e.g. style serialization outside of render), you will likely see a much smaller benefit after removing CSS-in-JS from the equation.<\/p>\n\n<p>Here is the raw data for those who are curious:<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuyygzdyyhng3yzzuq95e.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuyygzdyyhng3yzzuq95e.png\" alt=\"Spreadsheet showing render times between Emotion and non-Emotion Member Browser\" width=\"475\" height=\"344\"><\/a><\/p>\n\n<h2>\n  \n  \n  Our New Styling System\n<\/h2>\n\n<p>After we made up our minds to switch away from CSS-in-JS, the obvious question is: what should we be using instead? Ideally, we want a styling system that has performance similar to that of plain CSS while keeping as many of the benefits of CSS-in-JS as possible. Here are the primary benefits of CSS-in-JS that I described in the section titled \"The Good\":<\/p>\n\n<ol>\n<li>Styles are locally-scoped.<\/li>\n<li>Styles are colocated with the components they apply to.<\/li>\n<li>You can use JavaScript variables in styles.<\/li>\n<\/ol>\n\n<p>If you paid close attention to that section, you'll remember that I said that CSS Modules also provide locally-scoped styles and colocation. And CSS Modules compile to plain CSS files, so there is no runtime performance cost to using them.<\/p>\n\n<p>The main downside to CSS Modules in my mind is that, at end of the day, they are still plain CSS \u2014 and plain CSS is lacking features that improve DX and reduce code duplication. While <a href=\"https:\/\/developer.chrome.com\/blog\/help-css-nesting\/\" rel=\"noopener noreferrer\">nested selectors<\/a> are coming to CSS, they aren't here yet, and this feature is a huge quality of life boost for us.<\/p>\n\n<p>Fortunately, there is an easy solution to this problem \u2014 Sass Modules, which are simply CSS Modules written in <a href=\"https:\/\/sass-lang.com\/\" rel=\"noopener noreferrer\">Sass<\/a>. You get the locally-scoped styles of CSS Modules AND the powerful build-time features of Sass, with essentially no runtime cost. This is why Sass Modules will be our general purpose styling solution going forward.<\/p>\n\n<blockquote>\n<p>Side note: With Sass Modules, you lose benefit 3 of CSS-in-JS (the ability to use JavaScript variables in styles). Though, you can use an <code>:export<\/code> block in your Sass file to make constants from the Sass code available to JavaScript. This isn't as convenient, but it keeps things DRY.<\/p>\n<\/blockquote>\n\n<h3>\n  \n  \n  Utility Classes\n<\/h3>\n\n<p>One concern the team had about switching from Emotion to Sass Modules is that it would be less convenient to apply extremely common styles, like <code>display: flex<\/code>. Before, we would write:<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight tsx\"><code>\n\n<span class=\"p\">&lt;<\/span><span class=\"nc\">FlexH<\/span> <span class=\"na\">alignItems<\/span><span class=\"p\">=<\/span><span class=\"s\">\"center\"<\/span><span class=\"p\">&gt;<\/span>...<span class=\"p\">&lt;\/<\/span><span class=\"nc\">FlexH<\/span><span class=\"p\">&gt;<\/span>\n\n\n<\/code><\/pre>\n\n<\/div>\n\n<p>To do this using only Sass Modules, we would have to open the <code>.module.scss<\/code> file and create a class that applies the styles <code>display: flex<\/code> and <code>align-items: center<\/code>. It's not the end of the world, but it's definitely less convenient.<\/p>\n\n<p>To improve the DX around this, we decided to bring in a utility class system. If you aren't familiar with utility classes, they are CSS classes that set a single CSS property on the element. Usually, you will combine multiple utility classes to get the desired styles. For the example above, you would write something like this:<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight tsx\"><code>\n\n<span class=\"p\">&lt;<\/span><span class=\"nt\">div<\/span> <span class=\"na\">className<\/span><span class=\"p\">=<\/span><span class=\"s\">\"d-flex align-items-center\"<\/span><span class=\"p\">&gt;<\/span>...<span class=\"p\">&lt;\/<\/span><span class=\"nt\">div<\/span><span class=\"p\">&gt;<\/span>\n\n\n<\/code><\/pre>\n\n<\/div>\n\n<p><a href=\"https:\/\/getbootstrap.com\/\" rel=\"noopener noreferrer\">Bootstrap<\/a> and <a href=\"https:\/\/tailwindcss.com\/\" rel=\"noopener noreferrer\">Tailwind<\/a> are the most popular CSS frameworks that offer utility classes. These libraries have put a lot of design effort into their utility systems, so it made the most sense to adopt one of them instead of rolling our own. I had already been using Bootstrap for years, so we went with Bootstrap. While you can bring in the Bootstrap utility classes as a pre-built CSS file, we needed to customize the classes to fit our existing styling system, so I copied the relevant parts of the Bootstrap source code into our project.<\/p>\n\n<p>We've been using Sass Modules and utility classes for new components for several weeks now and are quite happy with it. The DX is similar to that of Emotion, and the runtime performance is vastly superior.<\/p>\n\n<blockquote>\n<p>Side note: We're also using the <a href=\"https:\/\/www.npmjs.com\/package\/typed-scss-modules\" rel=\"noopener noreferrer\">typed-scss-modules<\/a> package to generate TypeScript definitions for our Sass Modules. Perhaps the largest benefit of this is that it allowed us to define a <code>utils()<\/code> helper function that works like <a href=\"https:\/\/www.npmjs.com\/package\/classnames\" rel=\"noopener noreferrer\">classnames<\/a>, except it only accepts valid utility class names as arguments.<\/p>\n<\/blockquote>\n\n<h3>\n  \n  \n  A Note about Compile-Time CSS-in-JS\n<\/h3>\n\n<p>This article focused on runtime CSS-in-JS libraries like Emotion and styled-components. Recently, we've seen an increasing number of CSS-in-JS libraries that convert your styles to plain CSS at compile time. These include:<\/p>\n\n<ul>\n<li><a href=\"https:\/\/compiledcssinjs.com\/\" rel=\"noopener noreferrer\">Compiled<\/a><\/li>\n<li><a href=\"https:\/\/vanilla-extract.style\/\" rel=\"noopener noreferrer\">Vanilla Extract<\/a><\/li>\n<li><a href=\"https:\/\/linaria.dev\/\" rel=\"noopener noreferrer\">Linaria<\/a><\/li>\n<\/ul>\n\n<p>These libraries purport to provide a similar benefits to runtime CSS-in-JS, without the performance cost.<\/p>\n\n<p>While I have not used any compile-time CSS-in-JS libraries myself, I still think they have drawbacks when compared with Sass Modules. Here are the drawbacks I saw when looking at Compiled in particular:<\/p>\n\n<ul>\n<li>Styles are still inserted when a component mounts for the first time, which forces the browser to recalculate the styles on every DOM node. (This drawback was discussed in the section title \"The Ugly\".)<\/li>\n<li>Dynamic styles like the <code>color<\/code> prop in <a href=\"https:\/\/compiledcssinjs.com\/#speed-up-your-styles\" rel=\"noopener noreferrer\">this example<\/a> cannot be extracted at build time, so Compiled adds the value as a CSS variable using the <code>style<\/code> prop (a.k.a. inline styles). Inline styles are known to cause suboptimal performance when applied many elements.<\/li>\n<li>The library still inserts boilerplate components into your React tree as shown <a href=\"https:\/\/compiledcssinjs.com\/#speed-up-your-styles\" rel=\"noopener noreferrer\">here<\/a>. This will clutter up the React DevTools just like runtime CSS-in-JS.<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  Conclusion\n<\/h2>\n\n<p>Thanks for reading this deep dive into runtime CSS-in-JS. Like any technology, it has its pros and cons. Ultimately, it's up to you as a developer to evaluate these pros and cons and then make an informed decision about whether the technology is right for your use case. For us at Spot, the runtime performance cost of Emotion far outweighed the DX benefits, especially when you consider that the alternative of Sass Modules + utility classes still has a good DX while providing vastly superior performance.<\/p>\n\n<h2>\n  \n  \n  About Spot\n<\/h2>\n\n<p>At <a href=\"https:\/\/www.spotvirtual.com\/\" rel=\"noopener noreferrer\">Spot<\/a>, we're building the future of remote work. When companies go remote, they often lose the sense of connection and culture that was present in the office. Spot is a next-gen communication platform that brings your team together by combining traditional messaging and video conferencing features with the ability to create &amp; customize your own 3D virtual office. Please check us out if that sounds interesting!<\/p>\n\n<p>P.S. We're looking for talented software engineers to join the team! <a href=\"https:\/\/www.spotvirtual.com\/careers\/\" rel=\"noopener noreferrer\">See here for details.<\/a><\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcrf7kjbupc68abub05v6.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcrf7kjbupc68abub05v6.png\" alt=\"A picture of Spot\" width=\"800\" height=\"455\"><\/a><\/p>\n\n<p><em>This post was also published <a href=\"https:\/\/www.spotvirtual.com\/blog\/why-were-breaking-up-with-css-in-js\" rel=\"noopener noreferrer\">on the Spot blog<\/a>.<\/em><\/p>\n\n","category":["javascript","react","css","typescript"]},{"title":"Zero: One API Key to Rule Them All","pubDate":"Wed, 25 May 2022 22:34:01 +0000","link":"https:\/\/dev.to\/srmagura\/zero-one-api-key-to-rule-them-all-32l5","guid":"https:\/\/dev.to\/srmagura\/zero-one-api-key-to-rule-them-all-32l5","description":"<p><em>This post is sponsored by <a href=\"https:\/\/tryzero.com\/\" rel=\"noopener noreferrer\">Zero<\/a>.<\/em><\/p>\n\n<p><a href=\"https:\/\/tryzero.com\/\" rel=\"noopener noreferrer\">Zero<\/a> is an upcoming service that gives you a single API key that provides access to AWS, Stripe, Twilio, and tons of other APIs. This post is a sneak peek into what Zero will offer when the beta goes live. The team is aiming to launch in early June, so not too far away!<\/p>\n\n<h2>\n  \n  \n  What Problem Does It Solve?\n<\/h2>\n\n<p>Just about any modern cloud application needs to access external APIs for things like provisioning infrastructure, sending notifications, and processing payments, and each of these APIs will require an API token for authentication. It's not hard to manually manage the API keys under the following assumptions: <\/p>\n\n<ol>\n<li>You only use a few APIs.<\/li>\n<li>Your company is only a few people.<\/li>\n<li>You're OK sharing the API keys via email or a Google doc, even though this is potentially less secure.<\/li>\n<\/ol>\n\n<p>If any of these assumptions do not apply to your situation, managing API keys can become a real hassle. Imagine how much effort it would take to manage all your API tokens if:<\/p>\n\n<ol>\n<li>You use 20 different APIs across your company.<\/li>\n<li>Your company has 100 people who need API access, but only certain teams should have access to certain APIs.<\/li>\n<li>Security is paramount, so sending keys in emails is a no-go.<\/li>\n<\/ol>\n\n<p>This is where Zero comes in. In the next section, I'll cover how Zero helps with each of these difficulties.<\/p>\n\n<h2>\n  \n  \n  How Does Zero Address These Pain Points?\n<\/h2>\n\n<h3>\n  \n  \n  Problem: You use 20 different APIs across your company.\n<\/h3>\n\n<p><strong>Once you sign up for a Zero account, you gain instant access to many popular APIs.<\/strong> You no longer have to create separate accounts for Microsoft Azure, SendGrid, Shopify, and so on. This is a big time saver in the early stages of developing a product when you want to get moving as quickly as possible.<\/p>\n\n<p>Zero will provide you with a \"Zero token\" that grants access to one or more APIs. You can use it in your Node.js code like this:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"k\">import<\/span> <span class=\"nx\">zero<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@zero\/zero<\/span><span class=\"dl\">'<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">S3Client<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@aws-sdk\/client-s3<\/span><span class=\"dl\">'<\/span>\n<span class=\"k\">import<\/span> <span class=\"nx\">Stripe<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">stripe<\/span><span class=\"dl\">'<\/span>\n\n<span class=\"c1\">\/\/ The most popular APIs, like AWS, Stripe or Sendgrid are precreated for each <\/span>\n<span class=\"c1\">\/\/ account. One can start using them right after a sign up by simply requesting<\/span>\n<span class=\"c1\">\/\/ them in a Zero API call<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">creds<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"nf\">zero<\/span><span class=\"p\">({<\/span>\n  <span class=\"na\">apis<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"dl\">'<\/span><span class=\"s1\">aws<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">stripe<\/span><span class=\"dl\">'<\/span><span class=\"p\">],<\/span>\n  <span class=\"na\">token<\/span><span class=\"p\">:<\/span> <span class=\"nx\">process<\/span><span class=\"p\">.<\/span><span class=\"nx\">env<\/span><span class=\"p\">.<\/span><span class=\"nx\">ZERO_TOKEN<\/span><span class=\"p\">,<\/span>\n<span class=\"p\">}).<\/span><span class=\"nf\">fetch<\/span><span class=\"p\">()<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">client<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nc\">S3Client<\/span><span class=\"p\">({<\/span> <span class=\"na\">credentials<\/span><span class=\"p\">:<\/span> <span class=\"nx\">creds<\/span><span class=\"p\">.<\/span><span class=\"nx\">aws<\/span> <span class=\"p\">})<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">stripeApi<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">Stripe<\/span><span class=\"p\">(<\/span><span class=\"nx\">creds<\/span><span class=\"p\">.<\/span><span class=\"nx\">stripe<\/span><span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Problem: Your company has 100 people who need API access, but only certain teams should have access to certain APIs.\n<\/h3>\n\n<p>You can use the Zero web console to group users into teams:<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9oo64f6to84vn39zxne2.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9oo64f6to84vn39zxne2.png\" alt=\"Teams list in the Zero web console\"><\/a><\/p>\n\n<p>Then, you can assign each Zero token to one or more teams:<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc5vb1te1kiq55ug82iks.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc5vb1te1kiq55ug82iks.png\" alt=\"Token list in Zero web console\"><\/a><\/p>\n\n<p>This permissions model seems very easy to use while also being powerful enough to scale to larger organizations.<\/p>\n\n<h3>\n  \n  \n  Problem: Security is paramount, so sending keys in emails is a no-go.\n<\/h3>\n\n<p>All of your credentials are accessed either via the Zero web console or the Zero API, so there is no need to share API tokens via less secure means like email. When paired with the ability to give teams access to only the APIs they need, this design gives Zero the potential to be much more secure than manual API key management.<\/p>\n\n<h2>\n  \n  \n  How To Use It\n<\/h2>\n\n<p>Once the beta goes live, using Zero will go something like this:<\/p>\n\n<ol>\n<li>Sign up for a Zero Token.<\/li>\n<li>Pick the APIs that you need.<\/li>\n<li>Use the Zero SDK in your code to fetch credentials for individual APIs. (See the code sample above for what this will look like.)<\/li>\n<\/ol>\n\n<p>One thing you might be wondering is, what if I need to use a less common API that isn't integrated with Zero? Zero fully supports this scenario! Zero is not just a convenient shortcut for accessing APIs \u2014 more broadly speaking, it is a secrets management platform. This means Zero can store any secret key, even if it's not for one of the APIs that the service integrates with. Here's a screenshot of the UI you would use to upload a secret key for a less common API:<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6msjn18g4itv707bq8v6.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6msjn18g4itv707bq8v6.png\" alt=\"Adding an API key manually in Zero\"><\/a><\/p>\n\n<h2>\n  \n  \n  Q&amp;A with the Team\n<\/h2>\n\n<p>After reviewing the marketing materials, code snippets, and screenshots, I had a number of questions about the service. My contact on the Zero team, Artem, was happy to answer. Below is an edited version of my questions and his answers.<\/p>\n\n<p><strong>Q:<\/strong> I'm unclear about how Zero will connect to each of my accounts \/ subscriptions. For example, can I use Zero with my preexisting Twilio account?<\/p>\n\n<p><strong>A:<\/strong> Zero does not connect to your existing accounts. We create accounts (like AWS or Twilio) long before you sign up, store them in our safe storage, and then share some set of credentials with you once you sign up.<\/p>\n\n<p><strong>Q:<\/strong> Some teams will want to have different tokens for development, testing, and production. How would you accomplish this in Zero?<\/p>\n\n<p><strong>A:<\/strong> This is one is very good question! The credentials that we create are expected to be used mostly in dev environment. So when you need to start quick, and the only goal is speed, you just sign up to Zero, grab your credentials through SDK, and that\u2019s it, you are ready to build a thing instead of signing up for each service! Later on, when you go to production you\u2019ll need to create new set of credentials in the accounts that we will transfer to you right after sign up.<\/p>\n\n<p><strong>Q:<\/strong> Will Zero release API clients for programming languages other than JavaScript \/ TypeScript?<\/p>\n\n<p><strong>A:<\/strong> The initial release will have SDKs for JavaScript, TypeScript, and Go. We plan to add SDKs for other languages in the future.<\/p>\n\n<p><strong>Q:<\/strong> Are users able to view preexisting Zero tokens in the web console? I'm asking because many services do not allow you to view secrets after they are created.<\/p>\n\n<p><strong>A:<\/strong> Zero is a secrets manager, so yeah \u2014 you\u2019ll be able to observe a full secret in the web UI.<\/p>\n\n<h2>\n  \n  \n  Concerns\n<\/h2>\n\n<p>In the interest of providing a balanced take on the service, I'll share a few of my concerns about the service.<\/p>\n\n<ol>\n<li>I'm a bit sad that Zero is not intended to be used in production, as this seems to limit the usefulness of the service. Maybe the team can work on supporting this after the initial launch.<\/li>\n<li>It sounds like, when you sign up for Zero, they will transfer the preexisting accounts for each API provider to you. I'm not sure exactly how this process would work, but it seems like Zero will not help you manage the credentials for these service accounts. So even with Zero, there is still <em>some<\/em> need to manually manage credentials for each API provider.<\/li>\n<\/ol>\n\n<h2>\n  \n  \n  Final Thoughts\n<\/h2>\n\n<p>Zero has the potential to remove a lot of the tedium that's currently required to get access to the APIs you need. At the end of the day, anything that lets us spend less time setting up credentials and more time writing code is a good thing!<\/p>\n\n<p>Thank you to Zero for sponsoring my post and making it easy to review the service. I have high hopes for you all!<\/p>\n\n","category":["api","javascript","typescript","go"]},{"title":"Introducing SpotCoders, a Free Coding Meetup","pubDate":"Mon, 16 May 2022 16:25:16 +0000","link":"https:\/\/dev.to\/srmagura\/introducing-spotcoders-a-free-coding-meetup-3b4","guid":"https:\/\/dev.to\/srmagura\/introducing-spotcoders-a-free-coding-meetup-3b4","description":"<p><a href=\"https:\/\/www.meetup.com\/spotcoders\/\">SpotCoders<\/a> is a new virtual programming meetup that I'm starting! The meetup is open to anyone who wants to improve their JavaScript, TypeScript, and React skills by doing interview-style coding challenges in a small group environment. The problems will be targeted at beginner and intermediate level programmers.<\/p>\n\n<p>The unique thing about SpotCoders is that it will be hosted in <a href=\"https:\/\/spotvirtual.com\">Spot<\/a>, a virtual office &amp; event platform. In addition to being more fun than Zoom, Spot also makes it much more intuitive to do things like splitting into smaller groups. All you have to do is walk to a separate room in the 3D virtual world! (I happen to be an employee at Spot, by the way. That said, this is a personal project of mine and the company isn't making money from the meetup.)<\/p>\n\n<p>The <a href=\"https:\/\/www.meetup.com\/spotcoders\/events\/285936343\/\">first meeting<\/a> will be <strong>Saturday, May 28th from 12:00 pm \u2013 1:30 pm US Eastern Time<\/strong>. Anyone who can make this time is welcome to attend! The meeting is limited to 12 attendees, so make sure to RSVP sooner rather than later if you want to come. I may open it up to more people in the future if the meeting fills up quickly. Once you RSVP, you'll be able to see the invite link for joining the Spot world.<\/p>\n\n<p>Please read the <a href=\"https:\/\/www.meetup.com\/spotcoders\/\">group description on Meetup<\/a> to learn about the format of the meetings and what to expect. You can ignore where Meetup is showing Raleigh, NC as the location of the group \u2014 they require a physical location even for entirely virtual meetups like this one.<\/p>\n\n<p>I hope to see you there!<\/p>\n\n","category":["javascript","typescript","react","beginners"]},{"title":"Bad Habits of Mid-Level React Developers","pubDate":"Sat, 09 Apr 2022 19:03:09 +0000","link":"https:\/\/dev.to\/srmagura\/bad-habits-of-mid-level-react-developers-b41","guid":"https:\/\/dev.to\/srmagura\/bad-habits-of-mid-level-react-developers-b41","description":"<p>If you're a mid-level React developer looking to become an advanced React developer, this post is for you!<\/p>\n\n<p>I've been reviewing React code written by junior and mid-level developers on a daily basis for a couple of years now, and this post covers the most common mistakes I see. I'll be assuming you already know the basics of React and therefore won't be covering pitfalls like \"don't mutate props or state\". <\/p>\n\n<h2>\n  \n  \n  Bad Habits\n<\/h2>\n\n<p><strong>Each heading in this section is a bad habit that you should avoid!<\/strong><\/p>\n\n<p>I'll be using the classical example of a to-do list application to illustrate some of my points.<\/p>\n\n<h3>\n  \n  \n  Duplicating state\n<\/h3>\n\n<p><strong>There should be a single source of truth for each piece of state.<\/strong> If the same piece of information is stored in state twice, the two pieces of state can get out of sync. You can try writing code that synchronizes the two pieces of state, but this is an error prone band-aid rather than a solution.<\/p>\n\n<p>Here's an example of duplicate state in the context of our to-do list app. We need to track the items on the to-do list as well as which ones have been checked off. You could store two arrays in state, with one array containing all of the to-dos and the other containing only the completed ones:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight tsx\"><code><span class=\"kd\">const<\/span> <span class=\"p\">[<\/span><span class=\"nx\">todos<\/span><span class=\"p\">,<\/span> <span class=\"nx\">setTodos<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">useState<\/span><span class=\"o\">&lt;<\/span><span class=\"nx\">Todo<\/span><span class=\"p\">[]<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">([])<\/span>\n<span class=\"kd\">const<\/span> <span class=\"p\">[<\/span><span class=\"nx\">completedTodos<\/span><span class=\"p\">,<\/span> <span class=\"nx\">setCompletedTodos<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">useState<\/span><span class=\"o\">&lt;<\/span><span class=\"nx\">Todo<\/span><span class=\"p\">[]<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">([])<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>But this code is buggy at worst and smelly at best! Completed to-dos are stored in the state twice, so if the user edits the  text content of a to-do and you only call <code>setTodos<\/code>, <code>completedTodos<\/code> now contains the old text which is incorrect!<\/p>\n\n<p>There are a few ways to deduplicate your state. In this contrived example, you can simply add a <code>completed<\/code> boolean to the <code>Todo<\/code> type so that the <code>completedTodos<\/code> array is no longer necessary.<\/p>\n\n<h3>\n  \n  \n  Underutilizing reducers\n<\/h3>\n\n<p>React has two built-in ways to store state: <code>useState<\/code> and <code>useReducer<\/code>. There are also countless libraries for managing global state, with Redux being the most popular. Since Redux handles all state updates through reducers, I'll be using the term \"reducer\" to refer to both <code>useReducer<\/code> reducers and Redux reducers.<\/p>\n\n<p><code>useState<\/code> is perfectly fine when state updates are simple. For example, you can <code>useState<\/code> to track whether a checkbox is checked, or to track the <code>value<\/code> of a text input. <\/p>\n\n<p>That being said, <strong>when state updates become even slightly complex, you should be using a reducer.<\/strong> In particular, <strong>you should be using a reducer any time you are storing an array in state and the user can edit each item in the array.<\/strong> In the context of our to-do list app, you should definitely manage the array of to-dos using a reducer, whether that's via <code>useReducer<\/code> or Redux.<\/p>\n\n<p>Reducers are beneficial because:<\/p>\n\n<ul>\n<li>They provide a centralized place to define state transition logic.<\/li>\n<li>They are extremely easy to unit test.<\/li>\n<li>They move complex logic out of your components, resulting in simpler components.<\/li>\n<li>They prevent state updates from being overwritten if two changes occur simultaneously. Passing a function to <code>setState<\/code> is another way to prevent this.<\/li>\n<li>They enable performance optimizations since <code>dispatch<\/code> has a stable identity.<\/li>\n<li>They let you write mutation-style code with <a href=\"https:\/\/immerjs.github.io\/immer\/\">Immer<\/a>. You <em>can<\/em> use Immer with <code>useState<\/code>, but I don't think many people actually do this.<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Not writing unit tests for the low-hanging fruit\n<\/h3>\n\n<p>Developers are busy people and writing automated tests can be time consuming. When deciding if you should write a test, ask yourself, \"Will this test be impactful enough to justify the time I spent writing it?\" When the answer is yes, write the test!<\/p>\n\n<p>I find that mid-level React developers typically do not write tests, <strong>even when the test would take 5 minutes to write and have a medium or high impact!<\/strong> These situations are what I call the \"low-hanging fruit\" of testing. <strong>Test the low-hanging fruit!!!<\/strong><\/p>\n\n<p>In practice, this means writing unit tests for all \"standalone\" functions which contain non-trivial logic. By standalone, I mean pure functions which are defined outside of a React component. <\/p>\n\n<p>Reducers are the perfect example of this! Any complex reducers in your codebase should have nearly 100% test coverage. I highly recommend developing complex reducers with Test-Driven Development. This means you'll write at least one test for each action handled by the reducer, and alternate between writing a test and writing the reducer logic that makes the test pass.<\/p>\n\n<h3>\n  \n  \n  Underutilizing <code>React.memo<\/code>, <code>useMemo<\/code>, and <code>useCallback<\/code>\n<\/h3>\n\n<p>User interfaces powered by React can become laggy in many cases, especially when you pair frequent state updates with components that are expensive to render (React Select and FontAwesome, I'm looking at you.) The React DevTools are great for identifying render performance problems, either with the \"Highlight updates when components render\" checkbox or the profiler tab.<\/p>\n\n<p><strong>Your most powerful weapon in the fight against poor render performance is  <code>React.memo<\/code>,<\/strong> which only rerenders the component if its props changed. The challenge here is ensuring that the props don't change on every render, in which case <code>React.memo<\/code> will do nothing. You will need to employ the <code>useMemo<\/code> and <code>useCallback<\/code> hooks to prevent this.<\/p>\n\n<p>I like to proactively use <code>React.memo<\/code>, <code>useMemo<\/code>, and <code>useCallback<\/code> to prevent performance problems before they occur, but a reactive approach \u2014 i.e. waiting to make optimizations until a performance issue is identified \u2014 can work too.<\/p>\n\n<h3>\n  \n  \n  Writing <code>useEffect<\/code>s that run too often or not often enough\n<\/h3>\n\n<p>My only complaint with React Hooks is that <code>useEffect<\/code> is easy to misuse. <strong>To become an advanced React developer, you need to fully understand the behavior of <code>useEffect<\/code> and dependency arrays.<\/strong><\/p>\n\n<p>If you aren't using the <a href=\"https:\/\/reactjs.org\/docs\/hooks-rules.html#eslint-plugin\">React Hooks ESLint plugin<\/a>, you can easily miss a dependency of your effect, resulting in an effect that does not run as often as it should. This one is easy to fix \u2014 just use the ESLint plugin and fix the warnings.<\/p>\n\n<p>Once you do have every dependency listed in the dependency array, you may find that your effect runs too often. For example, the effect may run on every render and cause an infinite update loop. There's no \"one size fits all\" solution to this problem, so you'll need to analyze your specific situation to figure out what's wrong. I will say that, if your effect depends on a function, storing that function in a ref is a useful pattern. Like this:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight tsx\"><code><span class=\"kd\">const<\/span> <span class=\"nx\">funcRef<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">useRef<\/span><span class=\"p\">(<\/span><span class=\"nx\">func<\/span><span class=\"p\">)<\/span>\n\n<span class=\"nx\">useEffect<\/span><span class=\"p\">(()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">funcRef<\/span><span class=\"p\">.<\/span><span class=\"nx\">current<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">func<\/span>\n<span class=\"p\">})<\/span>\n\n<span class=\"nx\">useEffect<\/span><span class=\"p\">(()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ do some stuff and then call<\/span>\n    <span class=\"nx\">funcRef<\/span><span class=\"p\">.<\/span><span class=\"nx\">current<\/span><span class=\"p\">()<\/span>\n<span class=\"p\">},<\/span> <span class=\"p\">[<\/span><span class=\"cm\">\/* ... *\/<\/span><span class=\"p\">])<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Not considering usability\n<\/h3>\n\n<p>As a frontend developer, you should strive to be more than just a programmer. <strong>The best frontend developers are also experts on usability and web design, even if this isn't reflected in their job titles.<\/strong><\/p>\n\n<p>Usability simply refers to how easy it is to use an application. For example, how easy is it to add a new to-do to the list?<\/p>\n\n<p>If you have the opportunity to perform usability testing with real users, that is awesome. Most of us don't have that luxury, so we have to design interfaces based on our intuition about what is user-friendly. <strong>A lot of this comes down to common sense and observing what works or doesn't work in the applications you use everyday.<\/strong><\/p>\n\n<p>Here's a few simple usability best practices that you can implement today:<\/p>\n\n<ul>\n<li>Make sure clickable elements appear clickable. Moving your cursor over a clickable element should change the element's color slightly and cause the cursor to become a \"pointing hand\" i.e. <code>cursor: pointer<\/code> in CSS. <a href=\"https:\/\/getbootstrap.com\/docs\/5.1\/components\/buttons\/\">Hover over a Bootstrap button to see these best practices in action.<\/a>\n<\/li>\n<li>Don't hide important UI elements. Imagine a to-do list app when there \"X\" button that deletes a to-do is invisible until you hover over that specific to-do. Some designers like how \"clean\" this is, but it requires the user to hunt around to figure out how to perform a basic action.<\/li>\n<li>Use color to convey meaning. When displaying a form, use a bold color to draw attention to the submit button! If there's a button that permanently deletes something, it better be red! Check out <a href=\"https:\/\/getbootstrap.com\/docs\/5.1\/components\/buttons\/\">Bootstrap's buttons<\/a> and <a href=\"https:\/\/getbootstrap.com\/docs\/5.1\/components\/alerts\/\">alerts<\/a> to get a sense of this.<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Not working towards mastery of CSS &amp; web design\n<\/h3>\n\n<p><strong>If you want to create beautiful UIs efficiently, you must master CSS and web design.<\/strong> I don't expect mid-level developers to immediately be able to create clean and user-friendly interfaces while still keeping their efficiency high. It takes time to learn the intricacies of CSS and build an intuition for what looks good. But you need to be working towards this and getting better over time!<\/p>\n\n<p>It's hard to give specific tips on improving your styling skills, but here's one: <strong>master flexbox<\/strong>. While flexbox can be intimidating at first, it is a versatile and powerful tool that you can use to create virtually all of the layouts you'll need in everyday development.<\/p>\n\n<p>That covers the bad habits! See if you are guilty of any of these and work on improving. Now I'll zoom out and discuss some big picture best practices that can improve your React codebases.<\/p>\n\n<h2>\n  \n  \n  General Best Practices\n<\/h2>\n\n<h3>\n  \n  \n  Use TypeScript exclusively\n<\/h3>\n\n<p>Normal JavaScript is an okay language, but the lack type checking makes it a poor choice for anything but small hobby projects. Writing all of your code in TypeScript will massively increase the stability and maintainability of your application. <\/p>\n\n<p>If TypeScript feels too complex to you, keep working at. Once you gain fluency, you'll be able to write TypeScript just as fast as you can write JavaScript now.<\/p>\n\n<h3>\n  \n  \n  Use a data-fetching library\n<\/h3>\n\n<p>As I said in the \"Bad Habits\" section of this post, writing <code>useEffect<\/code>s correctly is hard. This is especially true when you are using <code>useEffect<\/code> directly to load data from your backend's API. You will save yourself countless headaches by using a library which abstracts away the details of data fetching. My personal preference is <a href=\"https:\/\/react-query.tanstack.com\/\">React Query<\/a>, though <a href=\"https:\/\/redux-toolkit.js.org\/rtk-query\/overview\">RTK Query<\/a>, <a href=\"https:\/\/swr.vercel.app\/\">SWR<\/a>, and <a href=\"https:\/\/www.apollographql.com\/docs\/react\/api\/react\/hooks\">Apollo<\/a> are also great options.<\/p>\n\n<h3>\n  \n  \n  Only use server rendering if you really need it\n<\/h3>\n\n<p>Server-side rendering (SSR) is one of the coolest features of React. It also adds a massive amount of complexity to your application. While frameworks like Next.js make SSR much easier, there is still unavoidable complexity that must be dealt with. If you need SSR for SEO or fast load times on mobile devices, by all means use it. But if you're writing a business application that does not have these requirements, please just use client-side rendering. You'll thank me later.<\/p>\n\n<h3>\n  \n  \n  Colocate styles with components\n<\/h3>\n\n<p>An application's CSS can quickly become a sprawling mess that no one understands. Sass and other CSS preprocessors add a few nice-to-haves but still largely suffer from the same problems as vanilla CSS.<\/p>\n\n<p>I believe styles should be scoped to individual React components, with the CSS colocated with the React code. I highly recommend reading <a href=\"https:\/\/kentcdodds.com\/blog\/colocation\">Kent C. Dodds' excellent blog post on the benefits of colocation.<\/a> Scoping CSS to individual components leads to component reuse as the primary method of sharing styles and prevents issues where styles are accidentally applied to the wrong elements.<\/p>\n\n<p>You can implement component-scoped, colocated styles with the help of <a href=\"https:\/\/emotion.sh\/\">Emotion<\/a>, <a href=\"https:\/\/styled-components.com\/\">styled-components<\/a>, or <a href=\"https:\/\/css-tricks.com\/css-modules-part-1-need\/\">CSS Modules<\/a>, among other similar libraries. My personal preference is Emotion with the <code>css<\/code> prop.<\/p>\n\n<p><strong>Update 2022-04-15:<\/strong> Clarified my statement that you should \"always\" use a reducer when the state is an array.<\/p>\n\n","category":["react","javascript","typescript"]},{"title":"The Easiest Way to Make a Mobile App? CodeSandbox!","pubDate":"Tue, 05 Oct 2021 14:05:35 +0000","link":"https:\/\/dev.to\/srmagura\/the-easiest-way-to-make-a-mobile-app-codesandbox-4gcd","guid":"https:\/\/dev.to\/srmagura\/the-easiest-way-to-make-a-mobile-app-codesandbox-4gcd","description":"<p><em>Now, before you come at me with a pitchfork \u2014 I'm saying this is the <strong>easiest<\/strong> way to make a mobile app, not the <strong>best<\/strong> way to develop an app for your use case.<\/em><\/p>\n\n<p>I started weightlifting about a year ago and I needed a way to time the break I took between sets. A mobile app was the obvious solution but I needed one that met my requirements:<\/p>\n\n<ul>\n<li>I wanted a huge, easy to press button to start the timer.<\/li>\n<li>I didn't want to have mess with text inputs or dropdowns to change the length of the timer.<\/li>\n<li>I didn't want an app with ads or complex features that I would never use.<\/li>\n<li>I wanted something free.<\/li>\n<\/ul>\n\n<p>While there may have been an app on Google Play that met my requirements, I didn't bother looking, <strong>because I knew I could create my own mobile app in 30 minutes.<\/strong> But how?<\/p>\n\n<h2>\n  \n  \n  Introducing CodeSandbox\n<\/h2>\n\n<p>If you haven't heard of <a href=\"https:\/\/codesandbox.io\/\">CodeSandbox<\/a>, it's a web-based development environment that makes it super easy to create JavaScript applications.<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--qfuG2utR--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/agby3mnietztm0p6z24g.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--qfuG2utR--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/agby3mnietztm0p6z24g.png\" alt=\"The CodeSandbox UI\"><\/a><\/p>\n\n<p>Unlike earlier tools like CodePen [1], CodeSandbox is a much closer approximation of a local development environment. You can create files, folders, and easily install packages from npm. While it's not a replacement for local development, CodeSandbox is perfect for demos, experiments, and minimal reproducible examples.<\/p>\n\n<h2>\n  \n  \n  Creating the Weightlifting Timer\n<\/h2>\n\n<p>The first step to creating an app on CodeSandbox is to select a template. I chose the React + TypeScript template, but you can use normal JavaScript, Vue, or whatever else floats your boat. I won't go into the details of the app's code since there are already many great resources for learning React and JavaScript timers. <\/p>\n\n<p>All things considered, it took around 30 minutes to finish the sandbox, <a href=\"https:\/\/codesandbox.io\/s\/weightlifting-timer-tkcsu?file=\/src\/App.tsx\">which you can view here.<\/a><\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--7ZaldYAb--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/wrzyo99ybuznueji6fu2.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--7ZaldYAb--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/wrzyo99ybuznueji6fu2.png\" alt=\"My weightlifting timer\"><\/a><\/p>\n\n<p><em>Clicking one of the buttons starts a timer for that many seconds. A sound is played when the timer finishes.<\/em><\/p>\n\n<h2>\n  \n  \n  Using the App\n<\/h2>\n\n<p>Getting the app on my phone was as simple as typing the sandbox URL, <code>tkcsu.csb.app<\/code>,  into Chrome's address bar on my phone. The CodeSandbox React templates are set up as <a href=\"https:\/\/web.dev\/progressive-web-apps\/\">Progressive Web Apps<\/a> (PWAs), so Chrome immediately prompted me to add the app to my home screen! [2] Here's how it looks:<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--coAWbjrd--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/sxknysxcscuwd933mxna.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--coAWbjrd--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/sxknysxcscuwd933mxna.png\" alt=\"The home screen icon\"><\/a><\/p>\n\n<p>I wasn't bothered at all by the CodeSandbox branding, but you might want your own icon and app name to show up instead. While this is normally easily accomplished by adding a <a href=\"https:\/\/web.dev\/add-manifest\/\">web app manifest<\/a>, I still got the CodeSandbox logo after adding my own <code>manifest.json<\/code>. It turns out CodeSandbox overwrites your manifest with its own. \ud83d\ude11 There's a <a href=\"https:\/\/github.com\/codesandbox\/codesandbox-client\/issues\/1532\">closed GitHub issue about this<\/a> with a hacky workaround if you're persistent.<\/p>\n\n<p>Manifest issues aside, the app works perfectly and has been used in \"production\" (by me) for over a year!<\/p>\n\n<h2>\n  \n  \n  SERIOUS Mobile Development \ud83d\ude20\n<\/h2>\n\n<p>CodeSandbox is a great way to make your first app or create a mobile utility for personal use. But if you want to get serious and create a professional-grade mobile app, there are better options. <\/p>\n\n<p>At one end of the spectrum, you have truly native iOS &amp; Android development. At the other end, you have PWAs and hybrid app frameworks like <a href=\"https:\/\/ionicframework.com\/\">Ionic<\/a>. For me, <a href=\"https:\/\/reactnative.dev\/\">React Native<\/a> hits the sweet spot. There's also Google's <a href=\"https:\/\/flutter.dev\/\">Flutter<\/a> and the upcoming <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/maui\/what-is-maui\">.NET MAUI<\/a>. I won't do a detailed comparison of these options here, but it may be the topic of a future post.<\/p>\n\n<h3>\n  \n  \n  Endnotes\n<\/h3>\n\n<p><strong>[1]<\/strong> To be fair, CodePen has improved since I last used it and now allows you to install npm packages.<br>\n<strong>[2]<\/strong> I've heard Apple isn't the biggest fan of PWAs, so you may not get prompted to add the app to your home screen if you use iOS. Of course, you can still bookmark the app and access it through your browser.<\/p>\n\n","category":["beginners","javascript","mobile"]},{"title":"C# Linting and Formatting Tools in 2021","pubDate":"Sun, 03 Oct 2021 19:50:57 +0000","link":"https:\/\/dev.to\/srmagura\/c-linting-and-formatting-tools-in-2021-bna","guid":"https:\/\/dev.to\/srmagura\/c-linting-and-formatting-tools-in-2021-bna","description":"<p><strong>tl;dr: Use SonarLint and optionally StyleCop.<\/strong><\/p>\n\n<p>The JavaScript ecosystem has amazing tools for formatting and statically analyzing your code: <a href=\"https:\/\/prettier.io\/\">Prettier<\/a> and <a href=\"https:\/\/eslint.org\/\">ESLint<\/a>. Both tools have nearly universal adoption and deliver significant value.<\/p>\n\n<p>But what about linting and formatting C# code?<\/p>\n\n<p>For formatting, there's Visual Studio's autoformatter (Edit &gt; Advanced &gt; Format Document), but it only formats a single file at a time and mainly fixes indentation and whitespace issues. It doesn't split up long lines, refuses to format certain language constructs, and is generally far less opinionated than Prettier.<\/p>\n\n<p>For linting, the C# compiler already has a few lint-like warnings, such as reminding you when you've forgotten to <code>await<\/code> an async method. These are helpful but only scratch the surface when compared to ESLint.<\/p>\n\n<p>Given the limitations of these built-in solutions, I set out to find something better.<\/p>\n\n<h2>\n  \n  \n  Formatting: dotnet-format \ud83e\udd14\n<\/h2>\n\n<p><a href=\"https:\/\/github.com\/dotnet\/format\">dotnet-format<\/a> is a formatting tool that's being included in the upcoming .NET 6 SDK. If you're not on .NET 6 yet, you can still easily install dotnet-format with <code>dotnet tool install dotnet-format<\/code> (pass the <code>-g<\/code> option for a global install). Johnny Reilly has a <a href=\"https:\/\/blog.johnnyreilly.com\/2020\/12\/22\/prettier-your-csharp-with-dotnet-format-and-lint-staged\/\">great post<\/a> about setting up dotnet-format together with lint-staged.<\/p>\n\n<p>I was really excited about dotnet-format when I heard about it, but sadly, it did not live up to the hype. I used it to reformat a medium C# 9 codebase and inspected the diff. And... <strong>all dotnet-format did was remove extraneous whitespace.<\/strong> dotnet-format did not<\/p>\n\n<ul>\n<li>Break up long lines of code<\/li>\n<li>Enforce consistent placement of curly braces<\/li>\n<li>Add or remove blank lines<\/li>\n<li>Reformat method signatures &amp; calls with inconsistent argument formatting such as\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight csharp\"><code>  <span class=\"k\">void<\/span> <span class=\"nf\">AddDocument<\/span><span class=\"p\">(<\/span><span class=\"kt\">string<\/span> <span class=\"n\">name<\/span><span class=\"p\">,<\/span> <span class=\"n\">FileId<\/span> <span class=\"n\">fileId<\/span><span class=\"p\">,<\/span> <span class=\"kt\">long<\/span> <span class=\"n\">fileSize<\/span><span class=\"p\">,<\/span>\n      <span class=\"n\">DocType<\/span> <span class=\"n\">type<\/span><span class=\"p\">,<\/span>\n      <span class=\"kt\">bool<\/span> <span class=\"n\">discoverable<\/span><span class=\"p\">,<\/span>\n      <span class=\"n\">CategoryId<\/span><span class=\"p\">?<\/span> <span class=\"n\">categoryId<\/span>\n  <span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>In dotnet-format's defense:<\/p>\n\n<ul>\n<li>It was extremely easy to set up.<\/li>\n<li>It can be completely automated \u2014 no manual intervention required.<\/li>\n<li>My test codebase was already formatted pretty well.<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  Formatting: StyleCop \ud83d\ude42\n<\/h2>\n\n<p><a href=\"https:\/\/github.com\/DotNetAnalyzers\/StyleCopAnalyzers\">StyleCop.Analyzers<\/a> is a open source suite of C# code analyzers that is installed via a <a href=\"https:\/\/www.nuget.org\/packages\/StyleCop.Analyzers\">NuGet package<\/a>. When you first install StyleCop and rebuild your solution, you'll likely see 10,000+ warnings. Wow! But don't worry; StyleCop has automatic fixes for most of these, and many of warnings are about trivial things like sorting your <code>using<\/code> statements alphabetically.<\/p>\n\n<h3>\n  \n  \n  Setup Instructions\n<\/h3>\n\n<p>Create a <code>Directory.Build.props<\/code> file next to your solution file and paste in the following XML.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight xml\"><code><span class=\"nt\">&lt;Project&gt;<\/span>\n  <span class=\"nt\">&lt;ItemGroup&gt;<\/span>\n    <span class=\"nt\">&lt;PackageReference<\/span> \n      <span class=\"na\">Include=<\/span><span class=\"s\">\"StyleCop.Analyzers\"<\/span> \n      <span class=\"na\">Version=<\/span><span class=\"s\">\"1.2.0-beta.354\"<\/span>\n      <span class=\"na\">PrivateAssets=<\/span><span class=\"s\">\"all\"<\/span> \n      <span class=\"na\">Condition=<\/span><span class=\"s\">\"$(MSBuildProjectExtension) == '.csproj'\"<\/span> \n    <span class=\"nt\">\/&gt;<\/span>\n  <span class=\"nt\">&lt;\/ItemGroup&gt;<\/span>\n<span class=\"nt\">&lt;\/Project&gt;<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>This adds the StyleCop.Analyzers NuGet package to every project in your solution. You should update the version number to whatever the latest is on NuGet.org. 1.2.0 introduces support for the latest C# features, so I recommend it even though it is still technically in beta.<\/p>\n\n<p>Next, add an <code>.editorconfig<\/code> file, also in the same directory as your solution file. <code>.editorconfig<\/code> is Microsoft's recommended way of configuring analyzers \u2014 <code>.ruleset<\/code> files are now deprecated. You can use Visual Studio's <code>.editorconfig<\/code> GUI to tweak the Formatting and Code Style settings, but a text editor is much more convenient for configuring analyzers. <a href=\"https:\/\/gist.github.com\/srmagura\/234c41af2de14568c5cdef841c71a29b\">Here's my <code>.editorconfig<\/code> file, which you're welcome to copy.<\/a><\/p>\n\n<p>Finally, rebuild the solution. StyleCop's suggestions will appear in the Error List and you'll get green Intellisense squigglies.<\/p>\n\n<h3>\n  \n  \n  Fixing StyleCop's Suggestions\n<\/h3>\n\n<p><strong>StyleCop's default ruleset is extremely opinionated and I recommend disabling rules that don't bring value to your team.<\/strong> For example, the <a href=\"https:\/\/github.com\/DotNetAnalyzers\/StyleCopAnalyzers\/blob\/master\/documentation\/SA1200.md\">SA1200<\/a> rule requires that <code>using<\/code> statements be placed within the <code>namespace<\/code> declaration. While there's nothing wrong with this coding style, it's not widely used since Visual Studio puts <code>using<\/code> statements outside the namespace when you create a new C# file. Both conventions are <a href=\"https:\/\/stackoverflow.com\/q\/125319\/752601\">equally valid<\/a>, so I recommend disabling this rule. You can do this by adding a line to your <code>.editorconfig<\/code>:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\"># Using directive should appear within a namespace declaration\n<\/span><span class=\"n\">dotnet_diagnostic<\/span><span class=\"p\">.<\/span><span class=\"n\">SA1200<\/span><span class=\"p\">.<\/span><span class=\"n\">severity<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">None<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>As you go through each StyleCop violation, you will encounter rules that are actually helpful. In every instance, I was able to automatically fix the violations across my entire solution via the quick fix menu.<\/p>\n\n<h3>\n  \n  \n  My Review\n<\/h3>\n\n<p><strong>StyleCop is a good tool and I recommend using it.<\/strong> <\/p>\n\n<p>I didn't agree with many of StyleCop's rules (27 to be precise), <em>but<\/em>, it really cleaned up my codebase and the automatic code fixes are awesome. I am slightly worried that StyleCop will become a distraction when I get back to real development, but we'll see.<\/p>\n\n<p>As the name suggests, StyleCop is primarily concerned with code <strong>style<\/strong>, not correctness. If we want to fix bugs in our code, we'll have to keep looking...<\/p>\n\n<h2>\n  \n  \n  Linting: SonarLint \ud83e\udd29\n<\/h2>\n\n<p><a href=\"https:\/\/www.sonarlint.org\/\">SonarLint<\/a> is an IDE extension and <a href=\"https:\/\/www.nuget.org\/packages\/SonarAnalyzer.CSharp\/\">NuGet package<\/a> that analyzes your code for bugs, vulnerabilities, and code smells. The core product is open source, though the company seems to be pushing the IDE extension which integrates with their commercial products.<\/p>\n\n<p>I tried out both the extension and the NuGet package and liked the NuGet package much better. Both options gave me Intellisense warnings, but only the NuGet package, SonarAnalyzer.CSharp, immediately showed me all the rule violations across my codebase. Moreover, a NuGet package is superior in a team setting since it will be downloaded automatically during build.<\/p>\n\n<h3>\n  \n  \n  Setup Instructions\n<\/h3>\n\n<p>SonarAnalyzer.CSharp is a collection of Roslyn analyzers just like StyleCop, so the setup is very similar. I'll be showing configuration files that include both StyleCop and SonarLint, but you can totally use SonarLint on its own.<\/p>\n\n<p>Edit the <code>Default.Build.props<\/code> file next to your solution to install SonarAnalyzer.CSharp into all projects:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight xml\"><code><span class=\"nt\">&lt;Project&gt;<\/span>\n  <span class=\"nt\">&lt;ItemGroup&gt;<\/span>\n    <span class=\"nt\">&lt;PackageReference<\/span> \n      <span class=\"na\">Include=<\/span><span class=\"s\">\"StyleCop.Analyzers\"<\/span> \n      <span class=\"na\">Version=<\/span><span class=\"s\">\"1.2.0-beta.354\"<\/span>\n      <span class=\"na\">PrivateAssets=<\/span><span class=\"s\">\"all\"<\/span> \n      <span class=\"na\">Condition=<\/span><span class=\"s\">\"$(MSBuildProjectExtension) == '.csproj'\"<\/span> \n    <span class=\"nt\">\/&gt;<\/span>\n    <span class=\"nt\">&lt;PackageReference<\/span>\n      <span class=\"na\">Include=<\/span><span class=\"s\">\"SonarAnalyzer.CSharp\"<\/span>\n      <span class=\"na\">Version=<\/span><span class=\"s\">\"8.29.0.36737\"<\/span>\n      <span class=\"na\">PrivateAssets=<\/span><span class=\"s\">\"all\"<\/span>\n      <span class=\"na\">Condition=<\/span><span class=\"s\">\"$(MSBuildProjectExtension) == '.csproj'\"<\/span>\n    <span class=\"nt\">\/&gt;<\/span>\n  <span class=\"nt\">&lt;\/ItemGroup&gt;<\/span>\n<span class=\"nt\">&lt;\/Project&gt;<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Your SonarLint rule customizations will go in the same <code>.editorconfig<\/code> file we created earlier. <a href=\"https:\/\/gist.github.com\/srmagura\/744ec1f356515eb3fe4b829f89c21a8c\">Here's my completed <code>.editorconfig<\/code>.<\/a> You can safely delete the StyleCop stuff if you're not using it.<\/p>\n\n<p>Once that's done, rebuild the solution and you should see new warnings.<\/p>\n\n<h3>\n  \n  \n  Fixing SonarLint's Suggestions\n<\/h3>\n\n<p>As you go through each warning, you'll notice that some have automatic fixes while others don't. If you encounter a rule you don't like, you can disable it using the same method I showed for StyleCop. I generally agreed with SonarLint's suggestions and only disabled 8 out of the 409 rules.<\/p>\n\n<p>When you encounter a rule violation you don't know how to fix, consult <a href=\"https:\/\/rules.sonarsource.com\/csharp\/RSPEC-112\">SonarLint's extensive rule database<\/a>.<\/p>\n\n<h3>\n  \n  \n  My Review\n<\/h3>\n\n<p><strong>The SonarLint NuGet package was everything I hoped for and I strongly recommend it.<\/strong><\/p>\n\n<p>By addressing each SonarLint warning, I was able to<\/p>\n\n<ul>\n<li>Learn about a <a href=\"https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/7irajf4fxriwwe926epv.png\">C# pitfall<\/a> that can easily result in bugs<\/li>\n<li>Identify several weak tests that made no assertions<\/li>\n<li>Have TODOs in the code appear as warnings in the Error List<\/li>\n<li>Fix a ton of inconsistently-named variables<\/li>\n<li>Fix methods that weren't using one of their arguments<\/li>\n<li>Add missing <code>static<\/code> modifiers to classes that only had static methods<\/li>\n<li>And more!<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  Linting: ReSharper \ud83d\ude41\n<\/h2>\n\n<p><a href=\"https:\/\/www.jetbrains.com\/resharper\/\">ReSharper<\/a> is a Visual Studio extension from JetBrains that adds advanced refactoring and static analysis. I used ReSharper for the first two years of my professional career, and <strong>found it to be a very helpful tool for learning C#'s advanced features.<\/strong> That said, I stopped using ReSharper due to its multiple downsides and I haven't looked back.<\/p>\n\n<ul>\n<li>ReSharper starts at $129\/year for individuals and $299\/year per user for organizations.<\/li>\n<li>Visual Studio + ReSharper is a slow and buggy mess.<\/li>\n<li>Visual Studio's built-in refactorings have been steadily catching up to ReSharper's.<\/li>\n<li>Once you're experienced with C#, ReSharper's warnings can be annoying rather than helpful.<\/li>\n<\/ul>\n\n<p>JetBrains does have their own .NET IDE, <a href=\"https:\/\/www.jetbrains.com\/rider\/\">Rider<\/a>, which may be worth checking out.<\/p>\n\n<h2>\n  \n  \n  Conclusion\n<\/h2>\n\n<p>I highly recommend SonarLint for identifying bugs and code smells. <\/p>\n\n<p>I'll be using StyleCop to enforce code formatting best practices, though dotnet-format is also a viable option. It's a tradeoff: StyleCop is more powerful but requires babysitting. dotnet-format is easy to install and can be completely automated as part of a precommit hook, but it won't fix many common style issues.<\/p>\n\n<h3>\n  \n  \n  Further Reading\n<\/h3>\n\n<ul>\n<li><a href=\"https:\/\/medium.com\/@michaelparkerdev\/linting-c-in-2019-stylecop-sonar-resharper-and-roslyn-73e88af57ebd\">Blog post: Linting C# in 2019<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/visualstudio\/code-quality\/use-roslyn-analyzers\">Microsoft docs: Analyzer configuration<\/a><\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Update 2021-10-05\n<\/h3>\n\n<ul>\n<li>Replace the now-deprecated <code>.ruleset<\/code> files with <code>.editorconfig<\/code>. Huge thanks to Honza Rame\u0161 for pointing this out!<\/li>\n<li>Clarify the pricing of ReSharper. Thanks Valentine Palazkov.<\/li>\n<\/ul>\n\n","category":"csharp"},{"title":"The Great Redux Toolkit Debate","pubDate":"Thu, 30 Sep 2021 13:41:10 +0000","link":"https:\/\/dev.to\/srmagura\/the-great-redux-toolkit-debate-5045","guid":"https:\/\/dev.to\/srmagura\/the-great-redux-toolkit-debate-5045","description":"<p>An <a href=\"https:\/\/dev.to\/srmagura\/comment\/1idl8\">offhand comment<\/a> I wrote one day while eating lunch sparked an unexpected and interesting debate with <a href=\"https:\/\/twitter.com\/acemarke\">Mark Erikson<\/a>, one of the maintainers of Redux.<\/p>\n\n<p><a href=\"https:\/\/redux.js.org\/\">Redux<\/a> has long been the go-to library for managing global state in React applications. <a href=\"https:\/\/redux-toolkit.js.org\/\">Redux Toolkit<\/a>, which Mark helped create, is a relatively new library that aims to be the \"official, opinionated, batteries-included toolset for efficient Redux development.\" This post will go into my thoughts on the benefits and potential drawbacks of Redux Toolkit.<\/p>\n\n<h2>\n  \n  \n  Why Redux is Awesome\n<\/h2>\n\n<ol>\n<li>\n<strong>It's unopinionated.<\/strong> Redux requires you to put your global state in a store, and to manage that state via reducers and actions. An action is a simple JavaScript object with a <code>type<\/code> property, and a reducer is a pure function that transforms the old state into the new state based on an action. Beyond this, everything else is up to you.<\/li>\n<li>\n<strong>It has a minimal API surface.<\/strong> Redux only has <a href=\"https:\/\/redux.js.org\/api\/api-reference\">5 top-level exports<\/a>, and only one of those, <code>createStore<\/code>, is essential.<\/li>\n<li>\n<strong>It's extremely versatile.<\/strong> Do you want your store to contain only the ID of the current user? Or do you want your store to track the state of every entity, page, widget, and input in your massive enterprise app? Whatever your use case, Redux and its large ecosystem have you covered.<\/li>\n<\/ol>\n\n<h2>\n  \n  \n  Why Redux is Hard\n<\/h2>\n\n<p>Redux is hard for the same reasons it is awesome.<\/p>\n\n<ol>\n<li>\n<strong>It's unopinionated.<\/strong> Redux doesn't tell you how to structure your application's state, reducers, or actions, so you have to make your own decisions.<\/li>\n<li>\n<strong>It has a minimal API surface.<\/strong> You'll quickly realize you need more than just <code>createStore<\/code> to create a useful application with Redux. A prime example of this is the need to fetch data from an API in response to an action.<\/li>\n<li>\n<strong>It's extremely versatile.<\/strong> There are so many different frontend architectures that are possible with Redux that it's easy to get lost. It took me a long time to figure out how Redux fit into the React applications I was building.<\/li>\n<\/ol>\n\n<h2>\n  \n  \n  Redux Toolkit to the Rescue\n<\/h2>\n\n<p>Redux Toolkit aims to eliminate first two of these pain points by providing an opinionated, convenient, and beginner-friendly approach to Redux development. Its features include:<\/p>\n\n<ul>\n<li>\n<code>createAction<\/code> \u2014 lets you define action creators, similar to <a href=\"https:\/\/github.com\/piotrwitek\/typesafe-actions\">typesafe-actions<\/a>. I'm a TypeScript die-hard so type safety is non-negotiable. \ud83d\ude06<\/li>\n<li>\n<code>createReducer<\/code> \u2014 allows you to write a reducer without a <code>switch<\/code> statement. Uses <a href=\"https:\/\/immerjs.github.io\/immer\/\">Immer<\/a> under the hood. Immer is amazing and you should use it in your reducers even if you don't plan to use Redux Toolkit.<\/li>\n<li>\n<code>createSlice<\/code> \u2014 a powerful helper that allows you to define both the reducer and actions for a slice of your state in one fell swoop.<\/li>\n<li>\n<code>createAsyncThunk<\/code> \u2014 allows you to start an API call in response to an action and dispatch another action when the call completes.<\/li>\n<li>\n<code>createEntityAdapter<\/code> \u2014 returns a set of prebuilt reducers and selector functions for performing CRUD on an entity.<\/li>\n<li>RTK Query \u2014 a <strong>library<\/strong> for fetching and caching server state in your Redux store. Can be compared to <a href=\"https:\/\/react-query.tanstack.com\/\">React Query<\/a> which aims to solve the same problems, but in a different way.<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  My Review of the Redux Toolkit (RTK) API\n<\/h2>\n\n<h3>\n  \n  \n  Overall Recommendation\n<\/h3>\n\n<ul>\n<li>If you're new to Redux, use RTK, but don't feel like you need to utilize all of its features. You can do a lot with just <code>createAction<\/code> and <code>createReducer<\/code>.<\/li>\n<li>If you're already using Redux and Immer, there's no reason you have to switch to Redux Toolkit. Only use it if you agree with its opinionated approach.<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  <code>createAction<\/code>\n<\/h3>\n\n<p>Not a new idea but a useful one nonetheless. Currently, typesafe-actions seems to be more powerful than RTK in this area because the typesafe-actions <code>getType<\/code> function correctly types <code>action.payload<\/code> in <code>switch<\/code> reducers. The <a href=\"https:\/\/github.com\/piotrwitek\/typesafe-actions#actiontype\"><code>ActionType<\/code><\/a> type helper is really nice too. I'd like to see RTK reach parity with typesafe-actions in this domain.<\/p>\n\n<p>If you can figure out how to write a type safe <code>switch<\/code> reducer with RTK, let me know!<\/p>\n\n<h3>\n  \n  \n  <code>createReducer<\/code>\n<\/h3>\n\n<p>As I said previously, Immer is really great. But Immer already works perfectly with <code>switch<\/code> reducers so  I don't see a huge benefit to <code>createReducer<\/code>.<\/p>\n\n<h3>\n  \n  \n  <code>createSlice<\/code>\n<\/h3>\n\n<p>I have a few concerns here. I like how in the traditional approach to Redux, you define your actions separately from your reducers. This separation of concerns allows you to lay out the operations your user can perform without getting bogged down in how those operations are implemented. <code>createSlice<\/code> eschews this separation and I'm not sure that's a step in the right direction. <\/p>\n\n<h3>\n  \n  \n  <code>createAsyncThunk<\/code>\n<\/h3>\n\n<p>By including <code>createAsyncThunk<\/code> in Redux Toolkit, the Redux team has made thunks the officially-recommended side effect model for Redux. I like how Redux itself is unopinionated regarding side effects, so I have mixed feelings about the built-in support for thunks.<\/p>\n\n<p>Of course, you can still use other side effect models like sagas and observables alongside Redux Toolkit. I'm a big fan of <a href=\"https:\/\/redux-saga.js.org\/\">Redux Saga<\/a>, which makes it straightforward to integrate Redux with your backend API while also enabling you to write incredibly powerful asynchronous flows. Sagas are written using generator functions and <code>yield<\/code> which does take some getting used to. <\/p>\n\n<p>Mark tells me that sagas can be overkill for common use cases and thunks fit better here. I can see this point of view, but I still find sagas to be more intuitive and will be sticking with them.<\/p>\n\n<h3>\n  \n  \n  <code>createEntityAdapter<\/code>\n<\/h3>\n\n<p>I'm concerned that <code>createEntityAdapter<\/code> could lead to designs that are overly CRUD-centric, favoring basic <code>add<\/code>, <code>update<\/code>, and <code>remove<\/code> actions over more meaningful, descriptive actions that are tailored to each entity. I'll admit that I don't fully understand the use case here. If <code>createEntityAdapter<\/code> saves you from writing tons of duplicate code, by all means use it.<\/p>\n\n<h3>\n  \n  \n  RTK Query\n<\/h3>\n\n<p>RTK Query really is a separate library that happens to live in the same package as Redux Toolkit. I think it would be better as a separate package, but that's just me. Fortunately, RTK Query is exported from a separate entry point, so it will never be included in your bundle if you don't use it.<\/p>\n\n<p>RTK Query seems complex to me, but my opinion might change if I tried it out. If you're looking for a data fetching solution, you should also consider <a href=\"https:\/\/react-query.tanstack.com\/\">React Query<\/a>. I evaluated the similar <a href=\"https:\/\/swr.vercel.app\/\">SWR<\/a> library but found it lacking some features that my team uses constantly. <\/p>\n\n<h2>\n  \n  \n  Mark's Response to my Claim that RTK is Overly Opinionated\n<\/h2>\n\n<p><a href=\"https:\/\/dev.to\/markerikson\/comment\/1ieni\">Read the full comment here!<\/a> In summary:<\/p>\n\n<blockquote>\n<p>As you can see, all of these APIs have a common theme:<\/p>\n\n<ul>\n<li>  These are things people were always doing with Redux, and have been taught in our docs<\/li>\n<li>  Because Redux didn't include anything built-in for this purpose, people were having to write this code by hand, or create their own abstractions<\/li>\n<li>  So we created standardized implementations of all these concepts that people could  <em>choose<\/em>  to use  <em>if they want to<\/em>, so that people don't  <em>have<\/em>  to write any of this code by hand in the future.<\/li>\n<\/ul>\n<\/blockquote>\n\n<h2>\n  \n  \n  What I Use in My Applications\n<\/h2>\n\n<h3>\n  \n  \n  My Last 4 React Web Apps\n<\/h3>\n\n<p>These are all medium-size single-page apps written entirely in React.<\/p>\n\n<ul>\n<li>Redux is used for about 10% of the overall application state, with local component state making up the other 90%. We deliberately only use Redux for state that needs to stay in memory when navigating between screens, for example information about the current user.<\/li>\n<li>We constructed our actions and reducers with typesafe-actions, Immer, and <code>switch<\/code> statements, whether using Redux or <code>useReducer<\/code>.<\/li>\n<li>A simple custom-made <code>useQuery<\/code> hook is used to fetch data from the backend. This data ends up in the local state of our <code>Page<\/code> components.<\/li>\n<li>There's a dash of Redux Saga to support login and persisting changes to complex order drafts that the user creates.<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  My React Native App\n<\/h3>\n\n<p>This app has to work offline so it made sense to put the majority of the app's state in Redux.<\/p>\n\n<ul>\n<li>Redux Saga is responsible for all the interaction with the backend API. This worked out quite well. There's a pretty complex saga for sending queued operations to the backend when a user comes back from being offline.<\/li>\n<li>The entire Redux store is persisted using <a href=\"https:\/\/www.npmjs.com\/package\/redux-persist\">redux-persist<\/a>. This is still magic to me \ud83d\ude02.<\/li>\n<li>Local component state is used for forms.<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  My Next React Web App\n<\/h3>\n\n<p>New projects are always exciting because they give you the chance to rethink your architecture and tech stack. Going forward, we will:<\/p>\n\n<ul>\n<li>Stick with typesafe-actions and <code>switch<\/code> reducers. It was a close call between this and switching to Redux Toolkit's <code>createAction<\/code> and <code>createReducer<\/code>. <strong>Update: The RTK team has succeeded in convincing me to give <code>createReducer<\/code> and <code>createSlice<\/code> a shot!<\/strong>\n<\/li>\n<li>Replace our homegrown <code>useQuery<\/code> with React Query. As a result, some state that we would have previously put in Redux will now be stored automatically in React Query's cache.<\/li>\n<li>Continue to use Redux Saga in a few places.<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  Further Reading\n<\/h2>\n\n<ul>\n<li><a href=\"https:\/\/blog.isquaredsoftware.com\/2019\/10\/redux-starter-kit-1.0\/\">Mark Erikson: Redux Toolkit 1.0<\/a><\/li>\n<li><a href=\"https:\/\/redux-toolkit.js.org\/\">The Redux Toolkit documentation<\/a><\/li>\n<\/ul>\n\n<h2>\n  \n  \n  Self-Promotion\n<\/h2>\n\n<ul>\n<li>Check out my new library, <a href=\"https:\/\/dev.to\/srmagura\/announcing-real-cancellable-promise-gkd\">real-cancellable-promise<\/a>!<\/li>\n<li>I'll be working on a new major version of <a href=\"https:\/\/github.com\/dvtng\/react-loading-skeleton\">react-loading-skeleton<\/a>. <a href=\"https:\/\/github.com\/dvtng\/react-loading-skeleton\/issues\/106\">Check out the roadmap here!<\/a>\n<\/li>\n<\/ul>\n\n","category":["redux","react","javascript","typescript"]},{"title":"Announcing real-cancellable-promise","pubDate":"Wed, 22 Sep 2021 13:30:36 +0000","link":"https:\/\/dev.to\/srmagura\/announcing-real-cancellable-promise-gkd","guid":"https:\/\/dev.to\/srmagura\/announcing-real-cancellable-promise-gkd","description":"<p>Hi! I'm Sam, a senior software developer at <a href=\"http:\/\/www.iticentral.com\/\">Interface Technologies<\/a>. <\/p>\n\n<p>Today I'm announcing the public release of <a href=\"https:\/\/github.com\/srmagura\/real-cancellable-promise\"><code>real-cancellable-promise<\/code><\/a>, a simple but robust cancellable promise library for JavaScript and TypeScript.<\/p>\n\n<p><code>real-cancellable-promise<\/code> solves two key problems that I've encountered in every React app I've ever written:<\/p>\n\n<h2>\n  \n  \n  Problem 1: setState after unmount\n<\/h2>\n\n<p><strong>Update: This warning has been removed in React 18! \ud83d\ude01<\/strong><\/p>\n\n<p>If you try to update your component's state after it has unmounted, you'll get<\/p>\n\n<blockquote>\n<p>Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.<\/p>\n<\/blockquote>\n\n<p>This can happen, for example, if your component starts an API call but the user navigates away before the API call completes. React tells you to \"cancel all asynchronous tasks\" but doesn't tell you <em>how<\/em> to do it. That's where <code>real-cancellable-promise<\/code> comes in.<\/p>\n\n<p><strong>The <code>CancellablePromise<\/code> class from <code>real-cancellable-promise<\/code> is just like a normal promise, except it has a <code>cancel<\/code> method.<\/strong> You can use the <code>cancel<\/code> method as the cleanup function in a <code>useEffect<\/code> to cancel your API call and prevent the setState after unmount warning.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"nx\">useEffect<\/span><span class=\"p\">(()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">cancellablePromise<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">listBlogPosts<\/span><span class=\"p\">()<\/span>\n        <span class=\"p\">.<\/span><span class=\"nx\">then<\/span><span class=\"p\">(<\/span><span class=\"nx\">setPosts<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">.<\/span><span class=\"k\">catch<\/span><span class=\"p\">(<\/span><span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">error<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"nx\">cancellablePromise<\/span><span class=\"p\">.<\/span><span class=\"nx\">cancel<\/span>\n<span class=\"p\">},<\/span> <span class=\"p\">[])<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Problem 2: Queries with variable parameters\n<\/h2>\n\n<p>API calls often have parameters that can change. A <code>searchUsers<\/code> API method might take in a search string and return users whose name matches that string. You can implement a React UI for this like:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight tsx\"><code><span class=\"kd\">function<\/span> <span class=\"nx\">searchUsers<\/span><span class=\"p\">(<\/span><span class=\"nx\">searchTerm<\/span><span class=\"p\">:<\/span> <span class=\"kr\">string<\/span><span class=\"p\">):<\/span> <span class=\"nb\">Promise<\/span><span class=\"o\">&lt;<\/span><span class=\"nx\">User<\/span><span class=\"p\">[]<\/span><span class=\"o\">&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"c1\">\/\/ call the API<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"kd\">function<\/span> <span class=\"nx\">UserList<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"p\">[<\/span><span class=\"nx\">searchTerm<\/span><span class=\"p\">,<\/span> <span class=\"nx\">setSearchTerm<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">useState<\/span><span class=\"p\">(<\/span><span class=\"dl\">''<\/span><span class=\"p\">)<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"p\">[<\/span><span class=\"nx\">users<\/span><span class=\"p\">,<\/span> <span class=\"nx\">setUsers<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">useState<\/span><span class=\"o\">&lt;<\/span><span class=\"nx\">User<\/span><span class=\"p\">[]<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">([])<\/span>\n\n    <span class=\"nx\">useEffect<\/span><span class=\"p\">(()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nx\">searchUsers<\/span><span class=\"p\">(<\/span><span class=\"nx\">searchTerm<\/span><span class=\"p\">)<\/span>\n            <span class=\"p\">.<\/span><span class=\"nx\">then<\/span><span class=\"p\">(<\/span><span class=\"nx\">setUsers<\/span><span class=\"p\">)<\/span>\n            <span class=\"p\">.<\/span><span class=\"k\">catch<\/span><span class=\"p\">(<\/span><span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">error<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">},<\/span> <span class=\"p\">[<\/span><span class=\"nx\">searchTerm<\/span><span class=\"p\">])<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"p\">&lt;<\/span><span class=\"nt\">div<\/span><span class=\"p\">&gt;<\/span>...<span class=\"p\">&lt;\/<\/span><span class=\"nt\">div<\/span><span class=\"p\">&gt;<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>But there are two issues here:<\/p>\n\n<ol>\n<li>If the API calls complete in a different order than they were initiated in, your UI shows the wrong data.<\/li>\n<li>If the search term changes while an API call is in progress, the in-progress API call is allowed to complete even though its result is now irrelevant. This wastes bandwidth and server resources.<\/li>\n<\/ol>\n\n<p><em>(Also in a real app you would definitely want to debounce <code>searchTerm<\/code>, but that's another topic.)<\/em><\/p>\n\n<p><code>real-cancellable-promise<\/code> resolves both issues by allowing you to cancel the in-progress API call when the search term changes:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"nx\">useEffect<\/span><span class=\"p\">(()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">cancellablePromise<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">searchUsers<\/span><span class=\"p\">(<\/span><span class=\"nx\">searchTerm<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">.<\/span><span class=\"nx\">then<\/span><span class=\"p\">(<\/span><span class=\"nx\">setUsers<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">.<\/span><span class=\"k\">catch<\/span><span class=\"p\">(<\/span><span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">error<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"nx\">cancellablePromise<\/span><span class=\"p\">.<\/span><span class=\"nx\">cancel<\/span>\n<span class=\"p\">},<\/span> <span class=\"p\">[<\/span><span class=\"nx\">searchTerm<\/span><span class=\"p\">])<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  But I'm using <a href=\"https:\/\/react-query.tanstack.com\/\">React Query<\/a>!\n<\/h3>\n\n<p>The <code>useQuery<\/code> hook from React Query has many advantages over making API calls in a <code>useEffect<\/code> like I showed in the previous example. React Query already handles API calls returning in the wrong order, but isn't able to abort the HTTP request without your help. <code>real-cancellable-promise<\/code> has you covered here \u2014 React Query will automatically call the <code>cancel<\/code> method of <code>CancellablePromise<\/code> when the query key changes. <a href=\"https:\/\/react-query.tanstack.com\/guides\/query-cancellation\">(Reference)<\/a><\/p>\n\n<h2>\n  \n  \n  How do I get started?\n<\/h2>\n\n<p><a href=\"https:\/\/github.com\/srmagura\/real-cancellable-promise\">Head on over to the README on GitHub<\/a> for instructions on integrating your HTTP library with <code>real-cancellable-promise<\/code> and for more detailed examples.<\/p>\n\n<h2>\n  \n  \n  Not just for React\n<\/h2>\n\n<p>I built <code>CancellablePromise<\/code> to solve problems I encountered in React development, but the library is not tied to React in any way. <code>real-cancellable-promise<\/code> is also tested in Node.js and React Native and should provide value in frontend applications built with other frameworks like Vue and Angular.<\/p>\n\n<h2>\n  \n  \n  The story behind the code\n<\/h2>\n\n<p>While this is the initial public release of the library, older versions of <code>CancellablePromise<\/code> have been used in production at Interface Technologies for over 3 years! It's one of the foundational components in our family of packages that enable us to deliver stable and user-friendly React apps quickly.<\/p>\n\n<p>Previous implementations of <code>CancellablePromise<\/code> were designed specifically to work with <code>async-await<\/code> and didn't have good support for traditional Promise callbacks via <code>then<\/code>, <code>catch<\/code>, and <code>finally<\/code>. The new <code>CancellablePromise<\/code> supports everything that normal Promises do, and the nice thing is that your promise stays cancellable no matter what you throw at it:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"kd\">const<\/span> <span class=\"nx\">cancellablePromise<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">asyncOperation1<\/span><span class=\"p\">()<\/span>\n    <span class=\"p\">.<\/span><span class=\"nx\">then<\/span><span class=\"p\">(<\/span><span class=\"nx\">asyncOperation2<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">.<\/span><span class=\"nx\">then<\/span><span class=\"p\">(<\/span><span class=\"nx\">asyncOperation3<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">.<\/span><span class=\"k\">catch<\/span><span class=\"p\">(<\/span><span class=\"nx\">asyncErrorHandler<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">.<\/span><span class=\"k\">finally<\/span><span class=\"p\">(<\/span><span class=\"nx\">cleanup<\/span><span class=\"p\">)<\/span>\n\n<span class=\"nx\">cancellablePromise<\/span><span class=\"p\">.<\/span><span class=\"nx\">cancel<\/span><span class=\"p\">()<\/span> <span class=\"c1\">\/\/ Cancels ALL the async operations<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Prior art\n<\/h2>\n\n<p>There are other libraries that enable Promise cancellation in JavaScript, namely <a href=\"https:\/\/www.npmjs.com\/package\/p-cancelable\">p-cancelable<\/a> and <a href=\"https:\/\/www.npmjs.com\/package\/make-cancellable-promise\">make-cancellable-promise<\/a>. <\/p>\n\n<p><code>make-cancellable-promise<\/code> is limited in that it doesn't provide the facility to cancel the underlying asynchronous operation (often an HTTP call) when <code>cancel<\/code> is called. It simply prevents your callbacks from running after cancellation occurs.<\/p>\n\n<p><code>p-cancelable<\/code> does let you cancel the underlying operation via the <code>onCancel<\/code> callback, but the library's API is limited compared to <code>real-cancellable-promise<\/code> in that  <\/p>\n\n<ul>\n<li>\n<code>then<\/code>, <code>catch<\/code>, or <code>finally<\/code> return a normal, non-cancellable Promise and,<\/li>\n<li>There is no support for returning a cancellable Promise from <code>Promise.all<\/code>, <code>Promise.race<\/code>, and <code>Promise.allSettled<\/code>. <code>real-cancellable-promise<\/code> provides these via <code>CancellablePromise.all<\/code>, <code>CancellablePromise.race<\/code>, and <code>CancellablePromise.allSettled<\/code>.<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  Stability\n<\/h2>\n\n<p><strong><code>real-cancellable-promise<\/code> has been tested extensively and is ready for production!<\/strong> The new <code>CancellablePromise<\/code> will be rolling out to one of our production apps next week, and our other apps will be updated soon after.<\/p>\n\n<h2>\n  \n  \n  Issues\n<\/h2>\n\n<p>Please post any issues you encounter in the GitHub repository.<\/p>\n\n","category":["javascript","typescript","react"]}]}}