<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ghaleb</title>
    <description>The latest articles on DEV Community by Ghaleb (@ghamadi).</description>
    <link>https://dev.to/ghamadi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F289131%2Fc53d1ed7-cd31-4809-92d1-1cc780b38a49.png</url>
      <title>DEV Community: Ghaleb</title>
      <link>https://dev.to/ghamadi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ghamadi"/>
    <language>en</language>
    <item>
      <title>Beyond Vibe Coding: 5 Lessons from a Side Project with Claude</title>
      <dc:creator>Ghaleb</dc:creator>
      <pubDate>Sat, 17 Oct 2026 14:25:10 +0000</pubDate>
      <link>https://dev.to/ghamadi/beyond-vibe-coding-5-lessons-from-a-side-project-with-claude-i58</link>
      <guid>https://dev.to/ghamadi/beyond-vibe-coding-5-lessons-from-a-side-project-with-claude-i58</guid>
      <description>&lt;p&gt;I experiment with skills often, constantly tweaking the ones I create and trying out skills from other people. I also run more than one agent setup, and some of my skills are tailored to specific projects. Keeping track of which skill lives where, and which copy is the latest, got messy fast.&lt;/p&gt;

&lt;p&gt;So I figured I'd build a CLI tool to manage my skills. The idea is simple: a single store holds the current copy of a skill, and the tool tracks where each of them goes. I decided I'd call it grimoire, and I estimated that it would take me a weekend or two to build with Claude.&lt;/p&gt;

&lt;p&gt;Twelve weekends later, it has ten commands, more than a thousand tests, and a pipeline that publishes it to npm. No project is as small as you initially think it will be, and an agent doesn't change that.&lt;/p&gt;

&lt;p&gt;With the first version of the project out, here are five lessons I learned from building it, starting with the one I didn't see coming.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Tests and CI are the biggest win, not shipping speed
&lt;/h2&gt;

&lt;p&gt;Most people celebrate the shipping speed of agentic coding. I agree that it's a huge advantage, but I think cheap tests and DevOps are the bigger win.&lt;/p&gt;

&lt;p&gt;Tests and a solid CI/CD pipeline are the cornerstone of maintaining any project. They're also the most tedious parts. On solo projects, they often get deferred to the "later" that never comes. Which is understandable, since time is a limited resource, and features are the part we actually enjoy building. Tests, on the other hand, just take precious time away from the next feature.&lt;/p&gt;

&lt;p&gt;Now, we get tests and CI/CD almost for free.&lt;/p&gt;

&lt;p&gt;Setting up the testing framework and the CI pipeline for grimoire took about half a day combined. All it needed was a handful of ground rules in &lt;code&gt;CLAUDE.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The pipeline tests the project on two operating systems and three Node versions, and it builds and publishes to npm. Additionally, &lt;em&gt;thorough&lt;/em&gt; tests get written with every feature, because AI agents are phenomenal at spotting edge cases and tracking every code branch that needs testing.&lt;/p&gt;

&lt;p&gt;With a foundation like this, I can take my time with features and still ship much faster than I used to. I can step away for weeks and still come back to a project that tells me if I broke something.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Remain in the loop, and hold the reins early
&lt;/h2&gt;

&lt;p&gt;Despite free tests, I found that vibe coding doesn't work for a project you plan to maintain. I tried it in the beginning and committed the agent's work without real reviews. Within a couple of weeks, even navigating the file structure became a challenge, and obnoxiously long comments and entangled modules made the code nearly impossible to follow.&lt;/p&gt;

&lt;p&gt;A project with spaghetti code only agents can follow is not your project anymore.&lt;/p&gt;

&lt;p&gt;The way out was a complete refactor that took several days and touched 85 files. I restructured the whole thing with Claude's help, but my input shaped the structure and set the rules moving forward, including two global rules for myself:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The agent is never allowed to commit anything without my explicit say-so.&lt;/li&gt;
&lt;li&gt;I never commit what I can't understand, if only at a high level.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Early on, there was a lot of back-and-forth. However, I found that remaining in the loop was an investment in a more streamlined workflow. As the project grew, patterns of my coding style and design preferences emerged, and LLMs &lt;em&gt;love&lt;/em&gt; patterns. The more I worked on the project, the shorter the reviews became.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Avoid the Waterfall trap
&lt;/h2&gt;

&lt;p&gt;AI agents make the Waterfall model tempting. It's easy to sit down one afternoon with your agent and design everything: features, architecture, system requirements, infrastructure, etc., and defer all implementation. The agent writes fast, and it gives you the illusion that it can see all the angles regardless of how large your design document becomes.&lt;/p&gt;

&lt;p&gt;That's the trap I fell into. I spent the first day only discussing design decisions at every level with Opus until I ended up with a 600-line markdown file. I was confident this would work because this document meant that I had all the rules set up for the model, and the path clear. The problem was that the document also crippled my ability to lead the agent. The size of the document meant that keeping track of the decisions in it, and making any edit, required complete reliance on the model. Subtle contradictions kept creeping into the document, and every prompt had a bloated context window early on. What started as a means to ground the agent ended up as the main source of my problems.&lt;/p&gt;

&lt;p&gt;The first thing I did during the refactor was mark the document deprecated. I restarted the work by defining the rules for the layers only. Then I designed and implemented vertical slices across the layers, feature by feature, until I had a working version. As I mentioned in lesson 2, the more I implemented, the more consistent the agent's output became.&lt;/p&gt;

&lt;p&gt;Agents take away the friction of the Waterfall model, but never its pitfalls. Plan the first slice, ship it, and let what you learn shape the next one.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Plan with high reasoning, execute with low
&lt;/h2&gt;

&lt;p&gt;Avoiding the Waterfall method doesn't mean planning less. Planning shifts to a per-feature basis. I found that implementing features gets more effective and more efficient when planning happens with higher reasoning, and implementation is run with lower reasoning on established plans.&lt;/p&gt;

&lt;p&gt;My workflow now runs through three skills I wrote:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;architect&lt;/code&gt; grounds a feature's requirements into a design document, and breaks the work into high-level parts.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pathfinder&lt;/code&gt; reads the design document and turns one part into a detailed, step-by-step implementation plan in structured JSON.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;roadrunner&lt;/code&gt; simply executes the JSON plan one step at a time without attempting to work around unexpected blockers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the heart of my planning skills is &lt;a href="https://github.com/mattpocock/skills" rel="noopener noreferrer"&gt;Matt Pocock's grill-me skill&lt;/a&gt;. It catches misinterpretations of the initial prompt early, and helps me account for all the different angles while planning. By the time &lt;code&gt;roadrunner&lt;/code&gt; starts, there are very few judgment calls left for it to get wrong.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The efficiency claim is based on my experience, not on any tests I ran. My guess is that a plan needs fewer output tokens at high reasoning than the code would, but that's just a guess. What I can say for certain is that this is how I work every day, on Claude's $20 plan.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  5. Your workflow is only as good as your skills
&lt;/h2&gt;

&lt;p&gt;Ad-hoc prompting breeds inconsistency. It's better to establish a structured workflow, and define skills that you constantly tweak and optimize based on your usage. Other people's skills are incredibly useful too, and can be built upon when creating your skills.&lt;/p&gt;

&lt;p&gt;A good rule of thumb: whenever you have to correct the agent the same way twice, that's a rule or a skill waiting to be written.&lt;/p&gt;

&lt;p&gt;That's also why grimoire exists. Once you have skills tailored to your workflows, you want them everywhere you work, without copying folders around by hand.&lt;/p&gt;

&lt;p&gt;My engineering skills are public in &lt;a href="https://github.com/ghamadi/skills" rel="noopener noreferrer"&gt;my skills repo&lt;/a&gt;. Take a look if you're interested, but keep in mind that none of them were built to be universally useful. Finally, if you juggle skills the way I do, give &lt;a href="https://www.npmjs.com/package/@ghamadi/grimoire" rel="noopener noreferrer"&gt;grimoire&lt;/a&gt; a try.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>claude</category>
      <category>vibecoding</category>
    </item>
    <item>
      <title>Data Privacy: How Much is too Much to Share for 'Free'?</title>
      <dc:creator>Ghaleb</dc:creator>
      <pubDate>Wed, 04 Oct 2023 09:27:05 +0000</pubDate>
      <link>https://dev.to/ghamadi/online-data-how-much-is-too-much-to-share-for-free-35el</link>
      <guid>https://dev.to/ghamadi/online-data-how-much-is-too-much-to-share-for-free-35el</guid>
      <description>&lt;p&gt;There's an excellent quote that I've always been a fan of:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When something online is free, you're not the customer, you're the product.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This sentiment has always deeply resonated with me and has often deterred me from sharing information online, even on platforms that are considered private.&lt;/p&gt;

&lt;p&gt;However, views on what qualifies as sensitive data differ from person to person. I wonder, which type of data makes a free service lose its allure?&lt;/p&gt;

&lt;p&gt;From my perspective, most personal data should be treated as sensitive. If I'm considering a service that primarily handles personal information in the cloud, I'd only opt for it if it operates on a viable and transparent business model (i.e., not a free service) and ensures end-to-end encryption.&lt;/p&gt;

&lt;p&gt;Without such a model—which admittedly might trade off some features for increased security—the potential dangers associated with various data forms become magnified in the face of breaches or leaks. Your exposed financial data paints a target on your back. An online diary brimming with intimate thoughts and insights into your mental health is a recipe for disaster. Furthermore, as AI continues its upward trajectory, heightening our reservations about both sharing and privately archiving photos or videos online is long overdue.&lt;/p&gt;

&lt;p&gt;Even data we might dismiss as "trivial" can have profound consequences when leaked or pooled together. The digital landscape is rife with tales of social engineering exploits, price discrimination, identity theft, financial fraud, ransomware, and more.&lt;/p&gt;

&lt;p&gt;Yet, the "free-of-charge" aspect of many services remains alluring. Some services are sometimes just nice to have and do not justify a fee. The question to me becomes: When does &lt;em&gt;privacy&lt;/em&gt; justify that fee?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>privacy</category>
      <category>security</category>
      <category>cloud</category>
    </item>
    <item>
      <title>The useEffect Conversations we Shouldn't be Having Anymore</title>
      <dc:creator>Ghaleb</dc:creator>
      <pubDate>Sun, 17 Sep 2023 09:00:00 +0000</pubDate>
      <link>https://dev.to/ghamadi/the-useeffect-conversations-we-shouldnt-be-having-anymore-5a3n</link>
      <guid>https://dev.to/ghamadi/the-useeffect-conversations-we-shouldnt-be-having-anymore-5a3n</guid>
      <description>&lt;p&gt;Many of the best practices and pitfalls of &lt;code&gt;useEffect&lt;/code&gt; have been discussed in depth in several great articles. However, its relationship with the component's state, and how limited that should be, is probably discussed to a lesser degree. More precisely, the exact purpose of &lt;code&gt;useEffect&lt;/code&gt; seems to allure beginners still.&lt;/p&gt;

&lt;p&gt;For instance, in a &lt;a href="https://www.reddit.com/r/reactjs/comments/15t4ql9/why_would_anyone_use_react/" rel="noopener noreferrer"&gt;post&lt;/a&gt; listing reasons &lt;em&gt;not&lt;/em&gt; to use React, a Reddit user made this argument:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;State is immutable in react. Meaning you’ll have to juggle your way around useEffect&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The way &lt;code&gt;useEffect&lt;/code&gt; is brought into this statement tells me that the person's pain with React is largely self-inflicted.&lt;/p&gt;

&lt;p&gt;Therefore, at the risk of being redundant, considering how well the React docs cover &lt;code&gt;useEffect&lt;/code&gt;, this post aims to be a comprehensive guide discussing the hook in detail—covering topics such as its fundamental purpose, how it works, and when to (and not to) use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Jump down to the summary 🙂&lt;/p&gt;




&lt;h2&gt;
  
  
  The Purpose of &lt;code&gt;useEffect&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;In React, &lt;code&gt;useEffect&lt;/code&gt; is a double-edged sword.&lt;/p&gt;

&lt;p&gt;It is a powerful tool in the world of functional components, but it will also nick the wielder who does not understand how functional components work, and when an effect is needed—which is rarely.&lt;/p&gt;

&lt;p&gt;Let's start with this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; React's answer to reactivity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words, its purpose is not to monitor some state elements through the dependency array to alter other state elements.&lt;/p&gt;

&lt;p&gt;An &lt;em&gt;effect&lt;/em&gt; is typically something you want to do after rendering takes place, and often involves interaction with the outside world. Like an event handler, it operates outside the main render flow. However, unlike an event handler, it isn't explicitly triggered; it simply runs after a component renders (more on this later).&lt;/p&gt;

&lt;p&gt;Effects can include a variety of tasks such as fetching data, subscribing to some event (notice: subscribing, not handling), manipulating the DOM directly, setting up timers, or cleaning up after certain actions.&lt;/p&gt;

&lt;p&gt;You can't do any of these things in the rendering code directly for two main reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The rendering code is responsible only for computing the values required to render.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You cannot guarantee how many times a component re-renders. Imagine adding an event listener or making an API call every time a component re-renders.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, what is the primary purpose of &lt;code&gt;useEffect&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;It is the escape hatch we need to perform &lt;strong&gt;&lt;em&gt;a side effect that should not be part of the rendering logic and is not related to an event&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That's all it is, and that's &lt;em&gt;all&lt;/em&gt; it should be used for. Excluding some exceptional edge cases, any other form of reliance on &lt;code&gt;useEffect&lt;/code&gt; signals bad design.&lt;/p&gt;




&lt;h2&gt;
  
  
  How &lt;code&gt;useEffect&lt;/code&gt; Works
&lt;/h2&gt;

&lt;p&gt;Now that we've established what &lt;code&gt;useEffect&lt;/code&gt; is meant for, let's delve into the specifics of how it works.&lt;/p&gt;

&lt;h3&gt;
  
  
  When does an effect run?
&lt;/h3&gt;

&lt;p&gt;First, let's take a quick look at the various phases a component goes through before being displayed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A render is triggered&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The component is rendered and diffed with the DOM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The changes are committed to the DOM&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These phases are always the same, and in that order, regardless of whether the component just mounted or was updated.&lt;/p&gt;

&lt;h4&gt;
  
  
  So where do effects come in?
&lt;/h4&gt;

&lt;p&gt;Effects run at the end of a commit, &lt;em&gt;after&lt;/em&gt; the screen updates.&lt;/p&gt;

&lt;p&gt;This ensures that the effect always has access to the most up-to-date state and props. It also makes sense, because effects shouldn't typically be involved in the rendering logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;EmptyComponent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This line is logged second&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This line is logged first&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that in mind, let's update the component's phases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A render is triggered&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The component is rendered and diffed with the DOM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The changes are committed to the DOM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Effects run&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Dependency Array
&lt;/h3&gt;

&lt;p&gt;If you only pass the callback argument to &lt;code&gt;useEffect&lt;/code&gt;, then that effect will run after every component render.&lt;/p&gt;

&lt;p&gt;However, you can - and in most cases you should - control when an effect runs by passing a second argument to the hook, known as the dependency array. With this array, the effect will run when the component first mounts, and on any subsequent re-render where the elements in the array change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Runs after every render&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Runs once after the initial render&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Runs after every render, provided that `count` changes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Be careful here, though. It is easy to fall into the trap of assuming the effect runs because the dependency array changed, which is false. Without triggering a render, the effect doesn't magically run.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counterRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// This effect will only run once, &lt;/span&gt;
  &lt;span class="c1"&gt;// no matter how many times counterRef.current is incremented&lt;/span&gt;
  &lt;span class="c1"&gt;// because updating a ref value does not trigger a render&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;counterRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;counterRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;counterRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Increment Counter
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that, let's update the component's phases again:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A render is triggered&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The component is rendered and diffed with the DOM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The changes are committed to the DOM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Effects run (subject to dependency array change)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Cleanup Callback
&lt;/h3&gt;

&lt;p&gt;Because &lt;code&gt;useEffect&lt;/code&gt; can run many times, we need a mechanism to "clean up" some code that is outside the component's control.&lt;/p&gt;

&lt;p&gt;Consider this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useTimeLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pageName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Time since loading &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pageName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;timeRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;s`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;pageName&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's assume we have this custom hook being called from various pages in our multi-route app. You load the app in &lt;code&gt;Page A&lt;/code&gt; and the logger begins working as expected. What happens when you go from &lt;code&gt;Page A&lt;/code&gt; to &lt;code&gt;Page B&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;If you guessed that you'll start getting mixed logs for both pages even though you left &lt;code&gt;Page A&lt;/code&gt;, you would be correct. Even though the component of &lt;code&gt;Page A&lt;/code&gt; unmounted, we never canceled its interval.&lt;/p&gt;

&lt;p&gt;To cancel an effect, we use the cleanup callback&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useTimeLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pageName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Time since loading &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pageName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;timeRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;s`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;timeRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;pageName&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;React will call your cleanup function &lt;em&gt;after&lt;/em&gt; committing the rendered changes and &lt;em&gt;before&lt;/em&gt; the effect runs next time.&lt;/p&gt;

&lt;p&gt;So, now the component's phases become:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A render is triggered&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The component is rendered and diffed with the DOM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The changes are committed to the DOM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Previously registered cleanup callbacks run (subject to dependency array change)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Effects run (subject to dependency array change)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cleanup callbacks are registered&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note that the cleanup function is also subject to the dependency array. Not all the registered cleanup functions run after a render; only those of which the dependency array changed.&lt;/p&gt;

&lt;p&gt;Also, just like all effects run when the component first mounts, all cleanup functions run when the component unmounts.&lt;/p&gt;

&lt;p&gt;To see this in action, consider this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;effect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cleanup&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;render&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the component first mounts, the logs show:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;render 0
effect 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the counter button is clicked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;render 1
cleanup 0
effect 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the component is unmounted at that point, we get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cleanup 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Effects and their cleanups should always be together
&lt;/h3&gt;

&lt;p&gt;In some rare cases, you might be tempted to have a &lt;code&gt;useEffect&lt;/code&gt; that only returns a cleanup function. Be careful if you do that because one of two things are very likely to have occurred:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;You don't have an effect&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You are cleaning up an effect that lives in another &lt;code&gt;useEffect&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the first case, you likely don't need &lt;code&gt;useEffect&lt;/code&gt; and you should reconsider what that cleanup callback is doing.&lt;/p&gt;

&lt;p&gt;The second case is generally a bad idea, which in edge cases can lead to unexpected behavior—&lt;em&gt;especially if the dependency arrays are different&lt;/em&gt;. Remember that the cleanup callback will run &lt;em&gt;before&lt;/em&gt; the next effect. If your cleanup has different dependencies than your effect, you may get into problems.&lt;/p&gt;

&lt;p&gt;In all cases, this is bad practice. I can't picture a scenario in which one might need to do this, except when converting class components to functional components. Sometimes when converting class components, we attempt to mimic the lifecycle hooks with &lt;code&gt;useEffect&lt;/code&gt; so &lt;code&gt;componentWillUnmount&lt;/code&gt; maps to a &lt;code&gt;useEffect&lt;/code&gt; with an empty array and a cleanup callback only.&lt;/p&gt;

&lt;p&gt;I once worked on a project that had such code, and it ended up being a bad call in every single instance, which brings us to our next point.&lt;/p&gt;




&lt;h2&gt;
  
  
  What &lt;code&gt;useEffect&lt;/code&gt; is NOT meant for
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. It is NOT a lifecycle hook
&lt;/h3&gt;

&lt;p&gt;Functional components are fundamentally different from class components. A functional component is designed to fully run on every render. In contrast, in class components, the instance persists until the component unmounts, and only certain methods are called more than once depending on the component's current lifecycle stage.&lt;/p&gt;

&lt;p&gt;Accordingly, mapping class components to functional components should be done on a fundamental level as well. We should not be looking at the class's lifecycle methods and thinking about which version of &lt;code&gt;useEffect&lt;/code&gt; to use for mapping it. Nor should we necessarily map all the class's state object directly for that matter. Instead, the component as a whole should be rethought within the bounds of the functional components paradigm.&lt;/p&gt;

&lt;p&gt;Always remember: Converting components is rarely a one-to-one mapping operation.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. It is NOT part of the rendering logic
&lt;/h3&gt;

&lt;p&gt;This is an intriguingly common misuse of the hook. If you have read React code, or gone through some tutorials, you have probably seen something like this before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;LoginForm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPassword&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isFormValid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsFormValid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Update `isFormValid` based on `email` and `password`&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isEmailValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isPassValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;setIsFormValid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isEmailValid&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;isPassValid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; 
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; 
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; 
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; 
        &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isFormValid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Login
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works, but it's bad practice for three main reasons:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Readability-wise, this doesn't scale
&lt;/h4&gt;

&lt;p&gt;We are detaching the event-triggered effect from the event handler. We have no way to go directly from the event handler to the effect, without reading the entire code. This becomes a much bigger problem with more complex components.&lt;/p&gt;

&lt;p&gt;This also leads to inconsistent patterns: sometimes you apply a visual change from the event handler, and sometimes the change comes from some &lt;code&gt;useEffect&lt;/code&gt; callback.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Performance-wise, this is bad
&lt;/h4&gt;

&lt;p&gt;Recall that an effect runs &lt;em&gt;after&lt;/em&gt; the render is committed. Let's walk this through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Our event handlers trigger a component re-render every time we type&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The changes are diffed and committed to the DOM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The effect runs, and it updates the state&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The updated state triggers another re-render&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So this code commits to the DOM twice after a single trigger. You can imagine how 'twice per trigger' could start being an issue if, say, you had a large table with editable fields.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. We are managing more state than necessary
&lt;/h4&gt;

&lt;p&gt;As a general rule, the more state the component manages, the more complex it becomes. Accepting this pattern above leads to the bad habit of adding unnecessary state.&lt;/p&gt;

&lt;p&gt;This case does not need &lt;code&gt;useEffect&lt;/code&gt; because it is not running an effect in the first place. Once we start dedicating &lt;code&gt;useEffect&lt;/code&gt; to its intended purpose, we start thinking in a different pattern, and we end up with code that is more predictable and more performant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;LoginForm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPassword&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// isFormValid becomes a derived value, not a state&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isEmailValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isPassValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isFormValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isEmailValid&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;isPassValid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; 
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; 
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; 
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; 
        &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isFormValid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Login
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if the computation of a derived value is expensive, the solution wouldn't be the dependency array of &lt;code&gt;usEffect&lt;/code&gt;. The solution is &lt;code&gt;useMemo&lt;/code&gt;!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isFormValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;someComplexValidator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;someComplexValidator&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. It is NOT an event listener
&lt;/h3&gt;

&lt;p&gt;Assume the code above wasn't validating the form, but was instead saving the form data to &lt;code&gt;localStorage&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️WARNING: This example is only to illustrate a misuse of &lt;code&gt;useEffect&lt;/code&gt;. Please don't store passwords in &lt;code&gt;localStorage&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You might argue that this is an effect because it is not part of the rendering logic, and decide to use &lt;code&gt;useEffect&lt;/code&gt; for it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The logic above is indeed a side effect. However, this effect is triggered by the &lt;code&gt;onChange&lt;/code&gt; events of the email and password input fields.&lt;/p&gt;

&lt;p&gt;While relying on &lt;code&gt;useEffect&lt;/code&gt; here does not entail adding state or rendering twice, it does detach the event-triggered-effect from the event handler. Despite resulting in a few more lines of code, it is far cleaner to keep &lt;em&gt;all&lt;/em&gt; event-handling logic in the event handler.&lt;/p&gt;




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

&lt;p&gt;The &lt;code&gt;useEffect&lt;/code&gt; hook is a powerful tool in a React developer's toolkit, but it is not a Swiss army knife designed for a multitude of tasks. Nor is it a tool to group event-triggered effects of multiple elements in one place.&lt;/p&gt;

&lt;p&gt;It is mainly an escape hatch for side effects that are not triggered by events. Your component will be much more predictable and maintainable if you understand its core purpose and stick to it.&lt;/p&gt;

&lt;p&gt;As a rule of thumb, only use &lt;code&gt;useEffect&lt;/code&gt; when two conditions apply:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The logic is a genuine side effect&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The logic is not triggered by an event&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If your &lt;code&gt;useEffect&lt;/code&gt; callback does not involve a side effect and involves render-related logic, then you likely need a computed value. If the computation is expensive and you only want it reacting to a specific state change, use &lt;code&gt;useMemo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The phases a component goes through are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A render is triggered&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The component is rendered and diffed with the DOM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The changes are committed to the DOM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Previously registered cleanup callbacks run (subject to dependency array change)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Effects run (subject to dependency array change)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cleanup callbacks are registered&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Just because the hook uses a dependency array, doesn't mean it is listening for changes. An effect runs after a render is triggered, not because a dependency value changed.&lt;/p&gt;

&lt;p&gt;Finally, do &lt;em&gt;not&lt;/em&gt; treat &lt;code&gt;useEffect&lt;/code&gt; as a lifecycle hook. Convert class components by rethinking them in the functional paradigm instead of just mapping their state and lifecycle methods.&lt;/p&gt;

</description>
      <category>react</category>
      <category>beginners</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>You Don't Need Redux: Embracing Component-Centric State Management in React</title>
      <dc:creator>Ghaleb</dc:creator>
      <pubDate>Thu, 01 Jun 2023 09:12:46 +0000</pubDate>
      <link>https://dev.to/ghamadi/embracing-component-centric-state-management-in-react-26hk</link>
      <guid>https://dev.to/ghamadi/embracing-component-centric-state-management-in-react-26hk</guid>
      <description>&lt;p&gt;It is relatively easy for an app to outgrow reliance on props for sharing state between components. Before the days of the Context API and hooks, centralized state management solutions (mainly Redux) were the go-to tools to efficiently read and update state across the app.&lt;/p&gt;

&lt;p&gt;The question now is whether such solutions remain necessary to scale an application. This post attempts to justify that the answer is "No". &lt;/p&gt;

&lt;p&gt;This is hopefully achievable by exploring the challenges that centralized state management introduces, and the way to circumvent the performance cost of the - much more flexible - Context API. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Pitfalls of Centralized State Management
&lt;/h2&gt;

&lt;p&gt;Centralizing all shared state, by definition, makes all shared state global. This can lead to leaner components as they become more focused on presentation than on the data itself. It also prevents prop-drilling which we can all agree is an absolute nightmare to track or - God forbid - refactor.&lt;/p&gt;

&lt;p&gt;However, these benefits come with a tradeoff in terms of code readability. Even assuming good design i.e., keeping what should be local state local, we will end up with more global state than necessary. Generally speaking, the more global state we have, the higher the maintenance impact in two main aspects:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Code Flow
&lt;/h3&gt;

&lt;p&gt;It is far easier to follow the code when the component's state is co-located with its rendering logic. When that's not possible, it remains easier to track the state of a closely related, small subtree of components that can be thought of as a module.&lt;/p&gt;

&lt;p&gt;There is rarely, if ever, a reason for the entire application to be a single set of tightly coupled atomic parts; which means there is rarely a justifying reason to have state accessible by all atomic parts.&lt;/p&gt;

&lt;p&gt;Tracking state, and therefore clearly understanding the &lt;em&gt;why&lt;/em&gt; behind your app's behavior, is greatly improved by respecting ownership. That is, when the logical owner of a state is the one initializing it and controlling which children at the lower levels of the app's component tree can access or mutate it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Code Complexity
&lt;/h3&gt;

&lt;p&gt;Global state inherently adds complexity because it can be altered from anywhere in the app which makes the consuming component less predictable, and harder to test. &lt;/p&gt;

&lt;p&gt;Dan Abramov, the co-creator of Redux, acknowledges that this is the main issue of using the library. &lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1241756566048694272-487" src="https://platform.twitter.com/embed/Tweet.html?id=1241756566048694272"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1241756566048694272-487');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1241756566048694272&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;First of all, I think it's interesting - to say the least - that the co-creator of Redux doesn't like it very much. &lt;/p&gt;

&lt;p&gt;More to the point, while Dan's response acknowledges that needlessly globalizing state can be detrimental, I think the original tweet was on to something. It is true that where the state is &lt;em&gt;managed&lt;/em&gt; is easy to track in Redux. However, can the same be said about knowing which components &lt;em&gt;use&lt;/em&gt; the state?&lt;/p&gt;

&lt;p&gt;Given a state, you know where the code lies by following the reducer chain. You also know what controls the state by following the actions. However, you don't readily know what the state affects—there is no easy way to know which &lt;code&gt;useSelector&lt;/code&gt; call is actually reading it. &lt;/p&gt;

&lt;p&gt;One argument here could be that this is a matter of design. We could limit the use of the central store to state that is truly global.&lt;/p&gt;

&lt;p&gt;But then it becomes questionable whether a full-featured library is actually needed to manage state that is strictly global. Except for maybe some edge cases, only a fraction of an app's total state &lt;em&gt;needs&lt;/em&gt; to be global, and such state typically doesn't change often (think user info).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Complexity of Managing Server State with Centralized Solutions
&lt;/h2&gt;

&lt;p&gt;When the app involves some sort of server state (like most apps do) the central store usually ends up being used as a cache for the server data, even though that is not its purpose. Additionally, "caching" using the central store adds a great deal of complexity because server state involves more than the data; it involves the state of the request as well.  &lt;/p&gt;

&lt;p&gt;To manage server state with a centralized solution, there are generally two approaches:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Defer the fetching action to the state management solution (e.g. thunks in Redux) which would handle the loading and error states of the requests, then store the response's data in the global store.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Handle the request along with its loading and error states inside an effect, then store the response's data in the global store.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To state the obvious, the last step is common between both approaches. The problem with this step is that we now have two sources of truth: the server, and the store. This clearly, and unnecessarily, introduces the complexity of keeping them in sync.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caching Solutions
&lt;/h3&gt;

&lt;p&gt;To keep the server as the single source of truth, we begin with the URL.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-699316556925243392-415" src="https://platform.twitter.com/embed/Tweet.html?id=699316556925243392"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-699316556925243392-415');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=699316556925243392&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;To elaborate on a succinct statement of wisdom, a URL generally provides two key pieces of information: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Where you are in the app&lt;/li&gt;
&lt;li&gt;Key data elements that define your state&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Dynamic data in the form of path and query parameters can take you a long way in providing your components with the state they need. You don't &lt;em&gt;need&lt;/em&gt; to store data across various stages of your app for it to work. What you need is the data's defining ID which you can grab from the URL and throw at the server. Naturally, this will have a performance impact on your app, but the important thing to note here is that it does not break functionality.&lt;/p&gt;

&lt;p&gt;As for the performance impact, while a central store &lt;em&gt;can&lt;/em&gt; be used to mitigate it, that's not a store's purpose. Dealing with that problem is where dedicated data-fetching and caching solutions like React Query and SWR come in.&lt;/p&gt;

&lt;p&gt;With features like deduping, auto re-fetching, and tracking the request's various state elements; these libraries not only eliminate the need for a global store to manage server state, but also allow for true separation of concerns that is in line with React's philosophy by allowing developers to fetch data where it is used—separating concerns by separating entities.&lt;/p&gt;

&lt;p&gt;Deduping and caching with timers like &lt;code&gt;staleTime&lt;/code&gt; and &lt;code&gt;cacheTime&lt;/code&gt; allow each component to handle its own server state without any performance impact. This plays a significant part in decoupling components—or at least decoupling subtrees of components.&lt;/p&gt;

&lt;p&gt;On the other hand, handling server state in a centralized store leads to managing more state than necessary directly in the app, and inevitably leads to tight coupling of components. Both factors significantly increase the complexity of your app, and there is little added value left in using such an approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Context API is not Problem Free
&lt;/h2&gt;

&lt;p&gt;Despite the arguments made so far, there is still one area in which a state-management library clearly trumps a regular context: performance.&lt;/p&gt;

&lt;p&gt;The main problem with the Context API is that when the &lt;code&gt;Provider&lt;/code&gt; re-renders due to some change in its state, &lt;em&gt;every&lt;/em&gt; &lt;code&gt;Consumer&lt;/code&gt; re-renders regardless of whether it was affected by that state or not. This is fundamentally different from how Redux state consumers behave. With Redux, only the components consuming the altered state re-render.&lt;/p&gt;

&lt;p&gt;At first glance, this might seem like a deal breaker. However, there are two important points to consider here: &lt;/p&gt;

&lt;h3&gt;
  
  
  1. This is not always an issue
&lt;/h3&gt;

&lt;p&gt;In cases where the subtree that re-renders is small, or the provider's state is not expected to change frequently (e.g. &lt;code&gt;AuthProvider&lt;/code&gt;); the performance difference becomes irrelevant. Difference in performance is only a factor when it is significant (even mildly significant); not when you are micro-optimizing.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. It is easy to achieve selective re-rendering with the Context API
&lt;/h3&gt;

&lt;p&gt;The key point to remember in the issue at hand is that the re-rendering chain begins when the state of the provider changes. What if we can have consumers subscribe to changes that are not part of React's state? In other words, what if we could achieve reactivity using the Context API without allowing the &lt;code&gt;Provider&lt;/code&gt; component to re-render?&lt;/p&gt;

&lt;p&gt;What Redux and other solutions do isn't magic. It is relatively simple to achieve similar selective reactivity using the Context API as well. Jack Harrington had an &lt;a href="https://www.youtube.com/watch?v=ZKlXqrcBx88" rel="noopener noreferrer"&gt;excellent video&lt;/a&gt; about this. And, to make a point, I actually &lt;a href="https://github.com/ghamadi/react-nimble-store/tree/main" rel="noopener noreferrer"&gt;abstracted away the logic&lt;/a&gt; of creating a smarter context where the provider doesn't blindly re-render consumers. The library is less than 100 lines of actual code (including type definitions). As I said, it's relatively simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making the Case for React Context
&lt;/h2&gt;

&lt;p&gt;Ultimately, the aim is to strike a balance between two extremes: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Mixing server and client state in one store and globalizing most of the app's state&lt;/li&gt;
&lt;li&gt;Prop drilling client state and having every other component make an API call even when it can easily grab a value from the parent&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I think it is possible to reach some point in the middle by adhering to these principles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Default to props until you start prop-drilling&lt;/li&gt;
&lt;li&gt;Create a context when props are not enough&lt;/li&gt;
&lt;li&gt;The context provider should be at the lowest possible level in the component tree. This is usually also the logical owner of the state&lt;/li&gt;
&lt;li&gt;The server state's parameters should in most cases be URL parameters&lt;/li&gt;
&lt;li&gt;Use a data-fetching/caching library&lt;/li&gt;
&lt;li&gt;The same principle for deciding where to place a context provider applies for deciding where to fetch the data&lt;/li&gt;
&lt;li&gt;When the state is expected to change frequently, or is needed globally, use a &lt;a href="https://github.com/ghamadi/react-nimble-store/tree/main" rel="noopener noreferrer"&gt;smarter context&lt;/a&gt; (or use that everywhere)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our focus should always be on building robust, maintainable applications, and our weapon of choice should be dictated by that. The heaviest sword is not always the right one, and while centralized state management solutions such as Redux were, and continue to be, powerful tools for building complex applications, they are not necessary for the majority of the cases.&lt;/p&gt;

&lt;p&gt;The rise of React's Context API, hooks, and data-fetching libraries like React Query present developers with the ability to manage state in a more component-centric, efficient, and flexible manner. These tools facilitate the co-location of state and logic, improve code readability, and simplify state flow. Relying on centralized stores trades off these features and the benefit is only clear in a small subset of applications where state needs to be globalized.&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>development</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Building a Portfolio: A Project Idea</title>
      <dc:creator>Ghaleb</dc:creator>
      <pubDate>Sun, 30 May 2021 20:19:36 +0000</pubDate>
      <link>https://dev.to/ghamadi/building-a-portfolio-a-project-idea-48bh</link>
      <guid>https://dev.to/ghamadi/building-a-portfolio-a-project-idea-48bh</guid>
      <description>&lt;p&gt;In the first part of this series, I introduced the general factors that generally make up a good project. Today, I will be suggesting a project idea, why it works, and some recommended features.&lt;/p&gt;

&lt;p&gt;I will also share a few resources that can be useful for full-stack developers when creating this project. The idea itself is not limited to web development, but I will be discussing it from the perspective of full-stack web developers.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Project: A Password Manager
&lt;/h1&gt;

&lt;p&gt;Password managers are not a new idea by any means, and managing passwords is not an &lt;em&gt;unsolved problem&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;There is a large number of solutions out there, so you will not be in lack of resources for inspiration. The large number of solutions, however, should not discourage you from implementing one yourself.&lt;/p&gt;

&lt;p&gt;I believe a password manager is comprehensive enough to be a good addition to most, if not all, portfolios. It is also complex enough to help you show your skills.&lt;/p&gt;

&lt;p&gt;Security is a very important component of any full-stack project, and password managers employ a suite of security concepts. Presenting a password manager not only equates presenting essential skills for full-stack development, but also your familiarity with security concepts. A password manager is also a useful project.&lt;/p&gt;

&lt;p&gt;It is one thing when you build an unpublished, dummy project. It is another thing entirely when that project is in active use. A published project conveys confidence in the implementation, and makes your sales pitch more convincing.&lt;/p&gt;

&lt;p&gt;A password manager is not limited to a small audience; it is useful to almost everyone. As such, finding a decent number of users in your circle of friends and family is not hard.&lt;/p&gt;

&lt;p&gt;I do have one warning here: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you are not at all familiar with concepts of security, or you do not intend to maximize security, then limit the users of the project to yourself, and avoid sensitive data (or keep it local).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another great aspect of this project idea, is that it inherently involves user management and non-trivial CRUD operations. A couple of unrelated tables (or document collections if you wish to use something like Firebase) will not be enough for a decent implementation. &lt;/p&gt;

&lt;p&gt;So, even if you do not care about maximizing security, your project will check most boxes in the list of skills needed for your full-stack position.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why it Works: Key Factors
&lt;/h1&gt;

&lt;h3&gt;
  
  
  1. Problem statement
&lt;/h3&gt;

&lt;p&gt;The importance of a password manager is well documented and is only expected to increase. As a matter of fact, password managers have become necessary if a user wishes to claim security. &lt;/p&gt;

&lt;p&gt;So, problem statement: ✔&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Data persistence
&lt;/h3&gt;

&lt;p&gt;Another obviously present component in this project. More importantly, the data model required for a proper password manager is not overly simple. &lt;/p&gt;

&lt;p&gt;At the very least, a basic - but useful - password manager needs to handle users, roles, and multiple types of secure items (not just accounts' passwords).&lt;/p&gt;

&lt;p&gt;So, clearly, data persistence: ✔&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Decent scope
&lt;/h3&gt;

&lt;p&gt;The scope of your application primarily depends on how much work you intend to invest in it. To justify this project idea however, we should discuss the minimal functionality required.&lt;/p&gt;

&lt;p&gt;The core features would be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication &amp;amp; authorization&lt;/li&gt;
&lt;li&gt;Client-side encryption &amp;amp; decryption of data&lt;/li&gt;
&lt;li&gt;A secure, random password generator&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other good-to-have features could be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom fields for secure items (allow user to add, remove, and rename fields of whatever secure items they wish to store)&lt;/li&gt;
&lt;li&gt;Editable templates of secure items&lt;/li&gt;
&lt;li&gt;Sharing encrypted data among users (public key encryption)&lt;/li&gt;
&lt;li&gt;Authenticating stored items (use case for HMAC)&lt;/li&gt;
&lt;li&gt;Master password reset (not a trivial problem to solve since the forgotten master password is needed to decrypt stored items)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the features above are important. You can either create a basic application with the core features, or expand it with the good-to-have features. Either way, you are still no where near nice-to-have features, and the scope of your application is already non-trivial.&lt;/p&gt;

&lt;p&gt;Decent scope: ✔&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Clean architecture
&lt;/h3&gt;

&lt;p&gt;Mostly because of the 'decent scope', you will increasingly suffer as you work on your project if you are not applying good coding practices. &lt;/p&gt;

&lt;p&gt;In other words, a project like this one almost forces you to carefully consider your architecture properly before implementing.&lt;/p&gt;

&lt;p&gt;This will be your responsibility as a developer. It cannot really be expanded upon here without explicitly discussing an implementation, which is beyond the scope of this article.&lt;/p&gt;

&lt;p&gt;Note that it might be a good idea to document your architecture if you intend to showcase your project later on.&lt;/p&gt;

&lt;p&gt;Clean architecture: ✔&lt;/p&gt;




&lt;h1&gt;
  
  
  Why it Works: Bonus Points
&lt;/h1&gt;

&lt;h3&gt;
  
  
  1. Encryption vs Hashing
&lt;/h3&gt;

&lt;p&gt;Remember, this is a project that emphasizes security. You do not have the option of storing passwords in plaintext and claiming that this is a dummy project and you wanted to focus on core functionality :) &lt;/p&gt;

&lt;p&gt;You will have to hash users' authentication passwords and encrypt their secure items. That means you will need to understand the exact differences between the two concepts, as well as the differences between the different algorithms within each realm. You will also need to understand best use cases for different algorithms to justify your choices.&lt;/p&gt;

&lt;p&gt;In short, this project helps you demonstrate good working knowledge in different security concepts.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. API consumption (optional)
&lt;/h3&gt;

&lt;p&gt;This was listed as an optional key component of a good project in my previous post. You will probably not need to consume an API for the core functionality of this app, but you can get creative with nice-to-have features.&lt;/p&gt;

&lt;p&gt;This is entirely optional, but you are expected to deal with APIs as an engineer, and as such, there is no harm in demonstrating comfort in using them.&lt;/p&gt;




&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;A password manager involves all the key components discussed to make a project fit for a full-stack developer's portfolio. &lt;/p&gt;

&lt;p&gt;More importantly, however, it also forces you to learn security concepts. These concepts are extremely relevant but often ignored or forgotten in projects, because they are not required for the app to function. &lt;/p&gt;




&lt;h1&gt;
  
  
  Resources
&lt;/h1&gt;

&lt;p&gt;Here's a list of resources that may be useful to building this web-based password manager:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=w68BBPDAWr8" rel="noopener noreferrer"&gt;How Password Managers Work - Computerphile&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;I cannot recommend this video enough&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cryptojs.gitbook.io/docs/" rel="noopener noreferrer"&gt;CryptoJS&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;A JavaScript crypto library &lt;/li&gt;
&lt;li&gt;Includes hashing and encryption algorithms&lt;/li&gt;
&lt;li&gt;Lacks asymmetric encryption&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/dchest/tweetnacl-js/blob/master/README.md#documentation" rel="noopener noreferrer"&gt;TweetNaCl.js&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;A JavaScript crypto library focused on encryption&lt;/li&gt;
&lt;li&gt;Includes asymmetric encryption but lacks HMAC &amp;amp; PBKDF2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/davidbau/seedrandom" rel="noopener noreferrer"&gt;seedrandom&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Seeded random number generator for JavaScript&lt;/li&gt;
&lt;li&gt;Might prove useful for a secure password generator&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>portfolio</category>
      <category>career</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Building a Portfolio: What to Look for in a Project</title>
      <dc:creator>Ghaleb</dc:creator>
      <pubDate>Mon, 24 May 2021 15:49:28 +0000</pubDate>
      <link>https://dev.to/ghamadi/building-a-portfolio-what-to-look-for-in-a-project-2kln</link>
      <guid>https://dev.to/ghamadi/building-a-portfolio-what-to-look-for-in-a-project-2kln</guid>
      <description>&lt;p&gt;This will be at two-part series in which I discuss my take on how &lt;br&gt;
to approach building a portfolio for new developers, and then suggest a project idea. &lt;/p&gt;

&lt;p&gt;The discussion mostly concerns full-stack development. Portfolios differ drastically across the different specializations of software engineering, so for this discussion to be of any use, we focus on one sector.&lt;/p&gt;




&lt;h1&gt;
  
  
  TL;DR
&lt;/h1&gt;

&lt;p&gt;Skip down to the Summary :) &lt;/p&gt;




&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;The importance of your portfolio varies from individual to another depending on several factors. However, it is accepted wisdom that if you plan to enter the software industry, you should have some number of projects built, even if only to showcase your knowledge.&lt;/p&gt;

&lt;p&gt;For career switchers, this is absolutely a must. So, being one myself, I spent a considerable amount of time researching the topic and looking for ideas to build projects.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Main Takeaway
&lt;/h1&gt;

&lt;p&gt;If I can state one conclusion from all of the different blog posts and videos I went through on the topic, it would be this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The idea itself doesn't really matter. The execution, and the motivation behind, it absolutely does.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By execution I obviously mean the implementation of the project. By motivation, I mean the reasons that made you believe this is a good project to showcase your ability as a full-stack candidate.&lt;/p&gt;

&lt;p&gt;This is not to say that simply listing project ideas is a bad approach. What I am saying is that developers trying to build a portfolio should understand what makes up a good project, because there might be a good idea lurking around in their own environment—one which cannot be found in lists of common topics. &lt;/p&gt;




&lt;h1&gt;
  
  
  What to Consider in a Project
&lt;/h1&gt;

&lt;p&gt;Now that we have established that the topic itself is not necessarily the property that gives the project its value, we should try to point out the ones that do.&lt;/p&gt;

&lt;p&gt;There a few components that you should look to have in your project when selecting a topic.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. A problem statement
&lt;/h3&gt;

&lt;p&gt;You want your project to show that you have made some effort to find a real-world problem and tried to solve it. &lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  Side note:
&lt;/h3&gt;

&lt;p&gt;A todo list is not a good candidate because it lacks creativity. You haven't looked hard enough if all you have found is an idea for a simple todo list.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Be careful here, though. This isn't a PhD thesis. You probably won't be able to find an unsolved problem, so don't spend your days looking instead of coding. Your goal is not to find &lt;em&gt;the perfect problem&lt;/em&gt;, but to find something you can justify the time spent solving.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Data persistence
&lt;/h3&gt;

&lt;p&gt;Unless your goal is to showcase ninja CSS skills, static pages won't cut it. The same goes for simple calculators. Just don't showcase a calculator. Please. &lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  Side note:
&lt;/h3&gt;

&lt;p&gt;If you do want to showcase ninja CSS skills, then by all means create such a project. Just don't make it your only one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A full-stack engineer deals with data, and your project should too. You need to show a project that efficiently deals with CRUD operations and not-so-trivial queries.&lt;/p&gt;

&lt;p&gt;Now, for the database used for said persistence, perhaps relational databases are not a must—with the popularity of the MEAN &amp;amp; MERN stacks and all. But in my opinion, the better candidate is the one that can justify the tools of choice. If you are not going to use a relational database, have reasons to back your decision.&lt;/p&gt;

&lt;p&gt;Regardless of the database system of choice, your database should be well designed, and your data manipulation should be efficient.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Decent scope
&lt;/h3&gt;

&lt;p&gt;This more concerned with your implementation than the topic. The problem statement does not need to be huge, but your implementation should not be limited.&lt;/p&gt;

&lt;p&gt;You should aim to mimic an actual product. Do not cut corners with features complementary to the core feature solving the problem. &lt;/p&gt;

&lt;p&gt;A web app without authentication and authorization, for example, is usually incomplete. If your app processes large amount of data, you should consider having import/export features and not just displaying data on your UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Clean architecture
&lt;/h3&gt;

&lt;p&gt;Again, a property concerned with your implementation. &lt;/p&gt;

&lt;p&gt;You need to have properly applied good software engineering practices and good practices of the tech stack you chose.&lt;/p&gt;

&lt;p&gt;Encapsulation and separation of concerns are the key factors here.&lt;/p&gt;

&lt;p&gt;You do not want an architecture with global variables everywhere being affected from multiple places in your code. You also do not want your data-handling logic jumbled up with your data-rendering logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Some form of an API consumption
&lt;/h3&gt;

&lt;p&gt;This may not be a must have, but I think it's worth considering. &lt;/p&gt;

&lt;p&gt;If your backend is not an API itself, it may be a good idea to pick a project that requires communicating with a third party API in your project; if only for the sake of demonstrating your skills and familiarity with the concept of asynchronous data fetching and (de)serialization of objects. &lt;/p&gt;




&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;In this article, I tried to articulate the key components that make up a good project based on my own research on the topic trying to build the resume that got me my first job. The five components listed may not be the only, or the most important, ones to look for in a full-stack app, but they are what I stood out to me.&lt;/p&gt;

&lt;p&gt;These are also the components I included in my own project before applying to the company that offered me my first job as a junior full-stack developer.&lt;/p&gt;

&lt;p&gt;In the next article, I will be suggesting an idea for a project that I have not come across often, and I will be detailing why I think it is a good choice when building your portfolio.&lt;/p&gt;

&lt;p&gt;Till then, please use the comments section to share your thoughts on the matter.&lt;/p&gt;




&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;When looking for projects to build, you need a project that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Has a problem statement:&lt;br&gt;
That is, the project solves a problem you can articulate to your audience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Requires data persistence:&lt;br&gt;
If the topic does not require a backend with a well-designed database, it is not a good fit for a full-stack application&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A scope beyond the feature that solves the problem:&lt;br&gt;
You need to show that you understand typical business requirements, and can develop a program with complementary features coherently implemented within the scope of your project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Clean architecture:&lt;br&gt;
Your project should demonstrate your grasp of the principle of "Separation of Concerns". You must demonstrate that you can develop with maintainability in mind.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Consumes some API:&lt;br&gt;
A preferred feature that will show your comfort with dealing with APIs and asynchronous data fetching.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>career</category>
      <category>codenewbie</category>
      <category>portfolio</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Vue or React?</title>
      <dc:creator>Ghaleb</dc:creator>
      <pubDate>Wed, 06 Jan 2021 12:55:05 +0000</pubDate>
      <link>https://dev.to/ghamadi/vue-or-react-iih</link>
      <guid>https://dev.to/ghamadi/vue-or-react-iih</guid>
      <description>&lt;p&gt;A couple of months ago, I chose Vue to be my point of entry to the frameworks realm in web development. I also decided to go in depth-first. So, I practiced barebones Vue, then used Vuetify, then - after getting sick of all the props and emits - I learned Vuex, and now I am playing around with Nuxt. In all this, I have not even glanced at the documentation of React.&lt;/p&gt;

&lt;p&gt;What I know about React, I know from occasional blog posts. A common claim I came upon was that Vue is simpler to learn than React. And that does not seem to come with a penalty in terms of performance or robustness. As I understand, from reading and not from experience, both frameworks are equally useful for projects of different scales.&lt;/p&gt;

&lt;p&gt;At least from my experience, as I work on my first meaningful web project, I find myself constantly impressed by how simple the development process is. Especially, when component libraries like Vuetify are utilized.&lt;/p&gt;

&lt;p&gt;Assuming my understanding is correct (and feel free to enlighten me if it isn't) I have two questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;With Vue.js readily available, is there any reason to learn React—other than the fact that React came first and therefore has the bigger market share?&lt;/li&gt;
&lt;li&gt;If no such reason exists, do you expect Vue to take over in the future? In other words, any reason for a startup project today not to be developed in Vue instead of React?&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>discuss</category>
      <category>webdev</category>
      <category>vue</category>
      <category>react</category>
    </item>
    <item>
      <title>Frameworks are Powerful and Awesome and Frightening</title>
      <dc:creator>Ghaleb</dc:creator>
      <pubDate>Thu, 29 Oct 2020 14:30:11 +0000</pubDate>
      <link>https://dev.to/ghamadi/frameworks-are-powerful-and-awesome-and-frightening-19i</link>
      <guid>https://dev.to/ghamadi/frameworks-are-powerful-and-awesome-and-frightening-19i</guid>
      <description>&lt;p&gt;I am new to all this. I haven't worked in the industry yet, and I am only now building my first project for my final year at college. I played with Flutter a bit before and, more recently, with VueJS a little bit more.&lt;/p&gt;

&lt;p&gt;Frameworks, for me, seem to be a double-edged sword. On one end, they make more projects feasible to individual developers and small teams. Projects are the best way to learn, and good projects enrich the industry, so that's cool. On the other end, they seriously lower the barriers to entry and make it harder to distinguish experience by looking at the end result alone. The code will always be revealing, of course, but the code is rarely looked at.&lt;/p&gt;

&lt;p&gt;For my final-year project I am using Firebase with Quasar. This is where the fear kicked in. The combination of tools I am using made things easy; maybe even &lt;em&gt;too&lt;/em&gt; easy. &lt;/p&gt;

&lt;p&gt;Initially, I planned out long durations for small tasks to account for my lack of experience. However, once the work began, the time in which I learned the concepts and finished my authentication form with the accompanying services, surprised me. I thought I would need two weeks just for tutorials, let alone having something functional. I needed three days for both.&lt;/p&gt;

&lt;p&gt;The Firebase SDK and Firestore rules did all the backend heavy-lifting, and Quasar made me laugh at myself as I looked at the elegant form that would have maybe cost me a month to build without those out-of-the-box components.&lt;/p&gt;

&lt;p&gt;So the natural question that followed was this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How afraid should we - the new kids on the block - be from competition in such a hot industry that keeps lowering the barriers to entry? What is the most efficient approach for a noob web developer to stand out?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I would love to hear how my fears are unfounded and how my question is invalid. This may be one of the rare occasions where one wishes for disapproving opinions. &lt;/p&gt;

&lt;p&gt;So, whether you agree, have tips on how to compete, or you completely disagree; please, do share.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>beginners</category>
      <category>career</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
