<?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: groundhog</title>
    <description>The latest articles on DEV Community by groundhog (@philrez).</description>
    <link>https://dev.to/philrez</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3576453%2F2397bca3-d9a8-4755-a68d-82a8a0b18877.jpeg</url>
      <title>DEV Community: groundhog</title>
      <link>https://dev.to/philrez</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/philrez"/>
    <language>en</language>
    <item>
      <title>ChatGPT Actions, Not Just Chat</title>
      <dc:creator>groundhog</dc:creator>
      <pubDate>Tue, 21 Oct 2025 19:56:42 +0000</pubDate>
      <link>https://dev.to/philrez/actions-not-just-chat-14n4</link>
      <guid>https://dev.to/philrez/actions-not-just-chat-14n4</guid>
      <description>&lt;h2&gt;
  
  
  React Component GPT:
&lt;/h2&gt;

&lt;p&gt;We need a GPT that understands our React components, knows our CSS variables, and can spit out code that's ready to use. This isn't about general knowledge; it's about &lt;em&gt;our&lt;/em&gt; knowledge. The standard GPT knowledge upload is fine for broad docs, but for precise component generation, we need control. That's where Actions come in.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem: Disconnected Knowledge
&lt;/h3&gt;

&lt;p&gt;Our design system lives in zeroheight. Our CSS variables are in a &lt;code&gt;.css&lt;/code&gt; file. Our React components are in &lt;code&gt;.jsx&lt;/code&gt; files. These are all discrete sources of truth. A generic LLM has no idea how they connect. If someone asks for a "primary button," it might give generic HTML, not our &lt;code&gt;Button&lt;/code&gt; component with &lt;code&gt;--color-brand-primary&lt;/code&gt;. Unacceptable.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution: Custom Actions to Bridge the Gap
&lt;/h3&gt;

&lt;p&gt;We build an API. This API becomes our "knowledge retrieval service." The GPT uses &lt;strong&gt;Actions&lt;/strong&gt; to call this API when it needs specific, localized data.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Extract Data (The ETL of our Design System):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;zeroheight Content:&lt;/strong&gt; Use the zeroheight API to pull down all component documentation. Store it, parse it, clean it. We're interested in usage guidelines, props, and design rationale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS Variables/Tokens:&lt;/strong&gt; This is crucial. Scrape our actual CSS files or token JSON. We need the variable names (&lt;code&gt;--color-brand-primary&lt;/code&gt;), their semantic meaning (e.g., "primary brand color"), and their default values. This data needs to be structured.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React Component Signatures:&lt;/strong&gt; Optionally, parse our actual React component files to extract prop types and default values. This helps the GPT understand the component's API.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GPT's Role (The Orchestrator):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The GPT's prompt is vital. We instruct it: "You are an expert React developer. When asked to create or style a component, use the &lt;code&gt;get_component_info&lt;/code&gt; action to retrieve specific details from our design system. &lt;strong&gt;Only use the CSS variables and component props returned by the action.&lt;/strong&gt; Do not hallucinate."&lt;/li&gt;
&lt;li&gt;When a user asks, "Generate a primary button component with a large size," the GPT identifies &lt;code&gt;Button&lt;/code&gt;, &lt;code&gt;primary&lt;/code&gt;, and &lt;code&gt;large&lt;/code&gt;. It then calls our API Action: &lt;code&gt;get_component_info(component_name='Button', style_attributes=['primary', 'large'])&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Our API returns the relevant zeroheight content, the &lt;code&gt;--color-brand-primary&lt;/code&gt; variable, and maybe &lt;code&gt;padding: var(--spacing-large)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The GPT uses &lt;em&gt;that specific information&lt;/em&gt; to generate the React component code, importing the correct component, applying the &lt;code&gt;className&lt;/code&gt; or &lt;code&gt;style&lt;/code&gt; with the correct CSS variables.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Why This Works
&lt;/h3&gt;

&lt;p&gt;This approach isn't about chat; it's about &lt;strong&gt;programmatic access to our design system's knowledge.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Accuracy:&lt;/strong&gt; We control the retrieval. The GPT can't invent variables or component usage patterns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintainability:&lt;/strong&gt; Our API can be updated independently of the GPT. If a variable name changes, we update our extraction and vector store, not the GPT's brain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is how we leverage LLMs for actual developer productivity, turning a design system into a code-generating assistant.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>chatgpt</category>
      <category>rag</category>
    </item>
    <item>
      <title>How I Built a GPT Action System to Ship Components 10x Faster</title>
      <dc:creator>groundhog</dc:creator>
      <pubDate>Tue, 21 Oct 2025 17:39:56 +0000</pubDate>
      <link>https://dev.to/philrez/how-i-built-a-gpt-action-system-to-ship-components-10x-faster-4hdk</link>
      <guid>https://dev.to/philrez/how-i-built-a-gpt-action-system-to-ship-components-10x-faster-4hdk</guid>
      <description>&lt;h2&gt;
  
  
  Supercharging Our Frontend:
&lt;/h2&gt;

&lt;p&gt;For the last year, our frontend velocity has been bottlenecked by the same thing that slows down most teams: &lt;strong&gt;component setup boilerplate and style guide enforcement.&lt;/strong&gt; I decided to tackle this head-on by building something that felt a bit like science fiction but will now be core to our daily workflow: a &lt;strong&gt;Custom GPT enhanced with targeted Actions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fymk4gzr5b39rzth650m9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fymk4gzr5b39rzth650m9.png" alt="GPT logic flow chart" width="800" height="730"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This system doesn't just &lt;em&gt;write&lt;/em&gt; code... it orchestrates an entire component lifecycle, from reading design tokens straight from our source of truth to opening a ready-to-review Pull Request.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Headache We Solved: Boilerplate and Drift
&lt;/h2&gt;

&lt;p&gt;Every developer knows the drill. You need a new &lt;code&gt;Card&lt;/code&gt; component. You open your editor, create four files (&lt;code&gt;Card.jsx&lt;/code&gt;, &lt;code&gt;Card.module.css&lt;/code&gt;, &lt;code&gt;Card.stories.jsx&lt;/code&gt;, &lt;code&gt;index.js&lt;/code&gt;), manually hunt down the correct spacing variable (&lt;code&gt;--space-2x&lt;/code&gt; vs. &lt;code&gt;--space-lg&lt;/code&gt;), and then spend time manually setting up the Storybook story.&lt;/p&gt;

&lt;p&gt;The problems were twofold:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Time Sink:&lt;/strong&gt; Pure setup time was stealing hours from actual problem-solving.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Style Drift:&lt;/strong&gt; Despite having a great design system, manual application meant developers sometimes missed a token or used a deprecated one, leading to visual inconsistencies down the line.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My goal was to automate the &lt;strong&gt;scaffolding and adherence&lt;/strong&gt; so developers could focus on the &lt;strong&gt;logic and UX.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Architecture: GPT + Actions as an Orchestrator
&lt;/h2&gt;

&lt;p&gt;The key wasn't just training the GPT on React; it was giving it reliable tools to interact with our environment. This is where &lt;strong&gt;Actions&lt;/strong&gt; come in. Think of the GPT as the brain and the Actions as its hands, capable of interacting with the external world.&lt;/p&gt;

&lt;p&gt;Here’s the step-by-step process for generating a new component:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Design Token Hook (Action 1: The Source of Truth)
&lt;/h3&gt;

&lt;p&gt;The first thing the GPT needs is the &lt;em&gt;official&lt;/em&gt; styling language.&lt;/p&gt;

&lt;p&gt;I configured an Action that uses a simple &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;fetch&lt;/code&gt; command to grab the content of our &lt;strong&gt;CSS variable file hosted on a GitHub raw link&lt;/strong&gt; (e.g., &lt;code&gt;https://raw.githubusercontent.com/org/design-tokens/main/tokens.css&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The GPT then parses this raw CSS, effectively building an internal, temporary map of all available tokens (&lt;code&gt;--color-brand-primary&lt;/code&gt;, &lt;code&gt;--spacing-4x&lt;/code&gt;, etc.). This ensures &lt;strong&gt;zero deviation&lt;/strong&gt; from the established style guide—it literally cannot use a variable that doesn't exist in the raw file.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Component Assembly Line (GPT Logic)
&lt;/h3&gt;

&lt;p&gt;With the token map accessible, the developer simply prompts: &lt;em&gt;"Build a large, primary-colored alert banner component that can display an icon and dismiss itself."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The GPT then simultaneously generates three crucial files, referencing the tokens it just fetched:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React Component (&lt;code&gt;AlertBanner.jsx&lt;/code&gt;):&lt;/strong&gt; Generates the functional component structure, props, and conditionally applies the appropriate CSS classes based on size/variant.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scoped Styles (&lt;code&gt;AlertBanner.module.css&lt;/code&gt;):&lt;/strong&gt; This is crucial. The GPT maps the abstract request ("primary-colored") to the concrete token (&lt;code&gt;background-color: var(--color-brand-primary);&lt;/code&gt;). This encapsulation is the foundation of style consistency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storybook Story (&lt;code&gt;AlertBanner.stories.jsx&lt;/code&gt;):&lt;/strong&gt; It automatically creates the boilerplate, sets up the control panel (Args) based on the component's props, and seeds it with a basic "Default" story.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Instant Validation (Action 2: The Live Preview)
&lt;/h3&gt;

&lt;p&gt;Before any code touches the repo, rapid feedback is essential. I built an Action that takes the generated component, CSS, and story code and automatically packages it into a standardized &lt;strong&gt;CodePen&lt;/strong&gt; or a similar sandboxed environment.&lt;/p&gt;

&lt;p&gt;This provides an immediate, interactive preview that the developer can share with the designer or product manager for quick sign-off, eliminating back-and-forth emails about local setup or screenshots.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Closing the Loop (Action 3: The PR Automation)
&lt;/h3&gt;

&lt;p&gt;Once the developer is happy, the final hurdle is the administrative work of contributing the code.&lt;/p&gt;

&lt;p&gt;A final command, &lt;em&gt;"Finalize and create PR"&lt;/em&gt;, triggers the last Action. This Action:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Pushes the new files to a newly created, temporary feature branch.&lt;/li&gt;
&lt;li&gt; Commits the changes with a clear message derived from the initial prompt.&lt;/li&gt;
&lt;li&gt; Opens a &lt;strong&gt;Pull Request&lt;/strong&gt; against our main branch, pre-filling the description with a summary of what was generated and linking to the CodePen preview.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Impact: Faster Iterations, Unified Teams
&lt;/h2&gt;

&lt;p&gt;This system isn't just a cool toy, it's a productivity multiplier.&lt;/p&gt;

&lt;p&gt;We've seen the time to &lt;strong&gt;"Component Ready for Review"&lt;/strong&gt; drop from an average of &lt;strong&gt;45 minutes to under 5 minutes&lt;/strong&gt; for standard components. This has had massive ripple effects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Faster Feature Velocity:&lt;/strong&gt; When scaffolding is trivial, the entire feature development process speeds up. We can move from concept to deployed feature in significantly tighter iteration cycles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design System Health:&lt;/strong&gt; Because the GPT is hard-wired to read the live token file, &lt;strong&gt;style drift is virtually eliminated.&lt;/strong&gt; Our codebase is cleaner, and the design system remains the single, untouchable source of truth.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer Joy:&lt;/strong&gt; My team members are genuinely happier. They spend their time on complex rendering logic, performance tuning, or tricky state management—the parts of software development that actually require human ingenuity—instead of remembering that the padding variable is &lt;code&gt;--spacing-4x&lt;/code&gt; and not &lt;code&gt;--spacing-large&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're drowning in boilerplate and fighting to keep your design system clean, I strongly suggest looking into how a GPT paired with robust, context-aware Actions can turn your most tedious frontend tasks into automated workflows. &lt;/p&gt;

</description>
      <category>productivity</category>
      <category>frontend</category>
      <category>automation</category>
      <category>ai</category>
    </item>
    <item>
      <title>Filtering Duplicates by ID (and Keeping the Rest!) in JavaScript</title>
      <dc:creator>groundhog</dc:creator>
      <pubDate>Tue, 21 Oct 2025 02:03:50 +0000</pubDate>
      <link>https://dev.to/philrez/filtering-duplicates-by-id-and-keeping-the-rest-in-javascript-26gf</link>
      <guid>https://dev.to/philrez/filtering-duplicates-by-id-and-keeping-the-rest-in-javascript-26gf</guid>
      <description>&lt;h2&gt;
  
  
  Smarter Data Handling:
&lt;/h2&gt;

&lt;p&gt;Working with data arrays in JavaScript, especially when fetched from APIs or user input, often means dealing with imperfections like duplicate entries or missing information. A common challenge is ensuring uniqueness based on a specific property, like an &lt;code&gt;id&lt;/code&gt;. But what if some items legitimately &lt;em&gt;don't&lt;/em&gt; have an &lt;code&gt;id&lt;/code&gt;, and you still want to include them in your final list?&lt;/p&gt;

&lt;p&gt;This post dives into a robust JavaScript technique to filter out objects with duplicate IDs, while &lt;em&gt;explicitly preserving&lt;/em&gt; any objects that don't have an &lt;code&gt;id&lt;/code&gt; property (or whose &lt;code&gt;id&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;).&lt;/p&gt;




&lt;h2&gt;
  
  
  The Duplicate ID Dilemma
&lt;/h2&gt;

&lt;p&gt;Imagine you have an array of data like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rawData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Product A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Uncategorized Item 1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// No ID!&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Product B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Product A - Updated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// Duplicate ID!&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Null ID Item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;     &lt;span class="c1"&gt;// ID is null!&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Product C&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Uncategorized Item 2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// Another item without an ID&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our goal is to get a clean array where:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Each &lt;code&gt;id&lt;/code&gt; (if present) appears only once.&lt;/li&gt;
&lt;li&gt; Any item &lt;em&gt;without&lt;/em&gt; an &lt;code&gt;id&lt;/code&gt; (or with &lt;code&gt;null&lt;/code&gt;/&lt;code&gt;undefined&lt;/code&gt; as an &lt;code&gt;id&lt;/code&gt;) is &lt;strong&gt;always included&lt;/strong&gt;, regardless of other items.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This requires a slightly more nuanced approach than a simple duplicate filter.&lt;/p&gt;




&lt;h2&gt;
  
  
  The &lt;code&gt;filter()&lt;/code&gt; + &lt;code&gt;Set&lt;/code&gt; Strategy (with a Twist)
&lt;/h2&gt;

&lt;p&gt;The most effective way to solve this is by combining &lt;code&gt;Array.prototype.filter()&lt;/code&gt; with a &lt;code&gt;Set&lt;/code&gt; object. The &lt;code&gt;Set&lt;/code&gt; is perfect for efficiently tracking unique values (our IDs) because checking if a value &lt;code&gt;has()&lt;/code&gt; been added to a &lt;code&gt;Set&lt;/code&gt; is very fast.&lt;/p&gt;

&lt;p&gt;The "twist" comes in how we handle objects that lack an &lt;code&gt;id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's break down the JavaScript implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUniqueItemsPreservingNoId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// We use a Set to keep track of IDs we've already encountered.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;seenIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Get the ID for the current item&lt;/span&gt;

    &lt;span class="c1"&gt;// --- IMPORTANT: Handle items without a valid ID first ---&lt;/span&gt;
    &lt;span class="c1"&gt;// If 'id' is falsy (undefined, null, 0, etc.), we immediately return true.&lt;/span&gt;
    &lt;span class="c1"&gt;// This ensures such items are ALWAYS included in the filtered array.&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// --- For items WITH a valid ID, check for duplicates ---&lt;/span&gt;
    &lt;span class="c1"&gt;// Check if we've already seen this specific ID.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isDuplicate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;seenIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// If it's the first time we're seeing this ID, add it to our Set.&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isDuplicate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;seenIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Return true only if it's NOT a duplicate (i.e., it's the first instance of this ID).&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isDuplicate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uniqueAndPreserved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getUniqueItemsPreservingNoId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawData&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="nx"&gt;uniqueAndPreserved&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What the Result Looks Like
&lt;/h3&gt;

&lt;p&gt;Running the &lt;code&gt;getUniqueItemsPreservingNoId&lt;/code&gt; function on our &lt;code&gt;rawData&lt;/code&gt; will yield:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Product A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Uncategorized Item 1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; 
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Product B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Null ID Item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;     
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Product C&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Uncategorized Item 2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how &lt;code&gt;Product A - Updated&lt;/code&gt; (which had a duplicate &lt;code&gt;id: 1&lt;/code&gt;) was filtered out, but &lt;code&gt;Uncategorized Item 1&lt;/code&gt;, &lt;code&gt;Null ID Item&lt;/code&gt;, and &lt;code&gt;Uncategorized Item 2&lt;/code&gt; (all lacking a standard &lt;code&gt;id&lt;/code&gt;) were kept.&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Works: The Breakdown
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;seenIds = new Set()&lt;/code&gt;&lt;/strong&gt;: We initialize an empty &lt;code&gt;Set&lt;/code&gt;. This will store all the unique &lt;code&gt;id&lt;/code&gt; values we encounter.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;arr.filter(item =&amp;gt; { ... })&lt;/code&gt;&lt;/strong&gt;: The &lt;code&gt;filter&lt;/code&gt; method iterates over each &lt;code&gt;item&lt;/code&gt; in our &lt;code&gt;rawData&lt;/code&gt; array. If the callback function returns &lt;code&gt;true&lt;/code&gt;, the &lt;code&gt;item&lt;/code&gt; is kept; if &lt;code&gt;false&lt;/code&gt;, it's discarded.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;if (!id) { return true; }&lt;/code&gt;&lt;/strong&gt;: This is the critical line.

&lt;ul&gt;
&lt;li&gt;It checks if &lt;code&gt;item.id&lt;/code&gt; is a "falsy" value (i.e., &lt;code&gt;undefined&lt;/code&gt;, &lt;code&gt;null&lt;/code&gt;, &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;''&lt;/code&gt;, &lt;code&gt;false&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;id&lt;/code&gt; is &lt;code&gt;undefined&lt;/code&gt; or &lt;code&gt;null&lt;/code&gt; (meaning no valid ID exists), we immediately return &lt;code&gt;true&lt;/code&gt;. This tells &lt;code&gt;filter&lt;/code&gt; to &lt;strong&gt;keep&lt;/strong&gt; this item without any further duplicate checks.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;seenIds.has(id)&lt;/code&gt;&lt;/strong&gt;: For items that &lt;em&gt;do&lt;/em&gt; have a valid &lt;code&gt;id&lt;/code&gt;, we check if our &lt;code&gt;seenIds&lt;/code&gt; &lt;code&gt;Set&lt;/code&gt; already contains this &lt;code&gt;id&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;seenIds.add(id)&lt;/code&gt;&lt;/strong&gt;: If the &lt;code&gt;id&lt;/code&gt; hasn't been seen before (&lt;code&gt;isDuplicate&lt;/code&gt; is &lt;code&gt;false&lt;/code&gt;), we add it to our &lt;code&gt;Set&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;return !isDuplicate;&lt;/code&gt;&lt;/strong&gt;: Finally, for items with an &lt;code&gt;id&lt;/code&gt;, we return &lt;code&gt;true&lt;/code&gt; only if it's &lt;em&gt;not&lt;/em&gt; a duplicate (i.e., it's the first time we've encountered this specific ID).&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Connecting the dots...
&lt;/h2&gt;

&lt;p&gt;This &lt;code&gt;filter()&lt;/code&gt; and &lt;code&gt;Set&lt;/code&gt; combination provides a clean, efficient, and readable way to handle a common data manipulation task. By adding the initial check for &lt;code&gt;!id&lt;/code&gt;, you gain the flexibility to enforce uniqueness where it matters (for items with IDs) while gracefully preserving all other data points. Master this pattern, and your data processing logic will be much more robust!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Finding and Updating Items in React Arrays</title>
      <dc:creator>groundhog</dc:creator>
      <pubDate>Tue, 21 Oct 2025 01:08:38 +0000</pubDate>
      <link>https://dev.to/philrez/finding-and-updating-items-in-react-arrays-4afa</link>
      <guid>https://dev.to/philrez/finding-and-updating-items-in-react-arrays-4afa</guid>
      <description>&lt;h2&gt;
  
  
  State Updates
&lt;/h2&gt;

&lt;p&gt;Managing arrays in &lt;strong&gt;React state&lt;/strong&gt; is a fundamental skill, especially when dealing with dynamic data like a list of users, products, or, in this case, &lt;strong&gt;selected items&lt;/strong&gt;. While array methods like &lt;code&gt;map&lt;/code&gt; are great for updating &lt;em&gt;every&lt;/em&gt; item, what happens when you only need to change one specific entry based on an ID or name? That's where the JavaScript method &lt;strong&gt;&lt;code&gt;findIndex()&lt;/code&gt;&lt;/strong&gt; shines, particularly when paired with the immutability principles of React state updates.&lt;/p&gt;

&lt;p&gt;This post will walk you through using &lt;code&gt;findIndex()&lt;/code&gt; to locate an item's index and then safely update that item in a &lt;strong&gt;TypeScript React&lt;/strong&gt; application.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why &lt;code&gt;findIndex()&lt;/code&gt; Over &lt;code&gt;find()&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;When you need to &lt;strong&gt;modify&lt;/strong&gt; an item in a React state array, you can't just change the item directly. React demands &lt;strong&gt;immutability&lt;/strong&gt;: you must create a &lt;em&gt;new&lt;/em&gt; array with the updated item.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;Array.prototype.find()&lt;/code&gt;&lt;/strong&gt;: Returns the &lt;strong&gt;actual element&lt;/strong&gt; (a copy of the object reference). You can modify this copy, but you still need its index to tell React &lt;em&gt;where&lt;/em&gt; to replace it in the original array structure.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;Array.prototype.findIndex()&lt;/code&gt;&lt;/strong&gt;: Returns the &lt;strong&gt;index&lt;/strong&gt; (a number) of the first element that satisfies the testing function. This index is exactly what you need to slice, spread, and reconstruct the array immutably.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The syntax for &lt;code&gt;findIndex&lt;/code&gt; is simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Practical Example: Managing Selections in TypeScript
&lt;/h2&gt;

&lt;p&gt;Let's imagine we have a list of tasks, and we want to toggle the &lt;code&gt;isSelected&lt;/code&gt; status for a specific task when a user clicks on it.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Define the State Interface
&lt;/h3&gt;

&lt;p&gt;First, in our TypeScript component, we define the structure for our state items.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// interfaces.ts or at the top of your component file&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;isSelected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Initializing State and the Update Function
&lt;/h3&gt;

&lt;p&gt;We'll set up our component with an initial list of tasks and the function that handles the toggle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ... (Task interface defined above)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TaskListManager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTasks&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Task&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Write blog post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isSelected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;102&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Review PRs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isSelected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;103&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Deploy feature branch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isSelected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="c1"&gt;// Function to toggle selection status&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleToggleSelection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;taskIdToToggle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// --- Step A: Find the Index ---&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;taskIdToToggle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Check if the item was found (findIndex returns -1 if not found)&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;===&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="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Task with ID &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;taskIdToToggle&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; not found.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// --- Step B: Create the New Item (Immutable Update) ---&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;updatedTask&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// Copy existing properties&lt;/span&gt;
      &lt;span class="na"&gt;isSelected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;isSelected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Toggle the value&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;// --- Step C: Create the New Array (Immutable State Update) ---&lt;/span&gt;
    &lt;span class="nf"&gt;setTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevTasks&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="c1"&gt;// 1. Items before the target index&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;prevTasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

      &lt;span class="c1"&gt;// 2. The newly updated item&lt;/span&gt;
      &lt;span class="nx"&gt;updatedTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

      &lt;span class="c1"&gt;// 3. Items after the target index&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;prevTasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&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="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;tasks&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// Dependency on 'tasks' array&lt;/span&gt;

  &lt;span class="c1"&gt;// ... (Rendering logic follows)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Breaking Down the Update Logic
&lt;/h2&gt;

&lt;p&gt;The core of the solution lies in &lt;strong&gt;Steps B and C&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Find the Index&lt;/strong&gt;: &lt;code&gt;const index = tasks.findIndex(...)&lt;/code&gt; efficiently locates the position of the target task.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Create the New Item&lt;/strong&gt;: We use the spread syntax (&lt;code&gt;...tasks[index]&lt;/code&gt;) to create a &lt;strong&gt;shallow copy&lt;/strong&gt; of the object at that index, then immediately override the &lt;code&gt;isSelected&lt;/code&gt; property. This ensures we're not modifying the original state object.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Create the New Array&lt;/strong&gt;: We leverage &lt;code&gt;Array.prototype.slice()&lt;/code&gt; along with the spread operator (&lt;code&gt;...&lt;/code&gt;) to build a &lt;strong&gt;brand new array&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;...prevTasks.slice(0, index)&lt;/code&gt;: Gets all elements &lt;em&gt;before&lt;/em&gt; the target.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;updatedTask&lt;/code&gt;: Inserts the modified object.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;...prevTasks.slice(index + 1)&lt;/code&gt;: Gets all elements &lt;em&gt;after&lt;/em&gt; the target.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This sequence guarantees that React detects the state change (because the array reference is new) and correctly triggers a re-render with the updated data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rendering Example
&lt;/h3&gt;

&lt;p&gt;You would then use this function in your JSX/TSX:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Inside the TaskListManager return statement&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;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Tasks&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&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;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; 
        &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; 
        &lt;span class="na"&gt;style&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="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
          &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1px solid #ccc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
          &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;5px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isSelected&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#e6ffe6&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}&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;handleToggleSelection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// Call the handler&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;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; - **Selected: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isSelected&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Yes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No&lt;/span&gt;&lt;span class="dl"&gt;'&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;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="si"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;You shouldn't use &lt;strong&gt;&lt;code&gt;Array.prototype.splice()&lt;/code&gt;&lt;/strong&gt; in React state updates because it is a &lt;strong&gt;mutating method&lt;/strong&gt;; it changes the original array directly. React requires that all state updates be &lt;strong&gt;immutable&lt;/strong&gt;, meaning you must create a &lt;strong&gt;new array&lt;/strong&gt; instead of modifying the existing one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Immutability is Key in React
&lt;/h2&gt;

&lt;p&gt;The primary reason to avoid &lt;code&gt;splice()&lt;/code&gt; (and other mutating methods like &lt;code&gt;push()&lt;/code&gt;, &lt;code&gt;pop()&lt;/code&gt;, or direct index assignment like &lt;code&gt;arr[0] = newItem&lt;/code&gt;) is how React handles rendering and change detection:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Change Detection:&lt;/strong&gt; React's default shallow comparison mechanism in components (especially with &lt;code&gt;React.memo&lt;/code&gt; or the class component &lt;code&gt;PureComponent&lt;/code&gt;) only checks if the state or prop &lt;strong&gt;reference&lt;/strong&gt; has changed.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  * If you use `splice()`, the array is modified *in place*, but the **memory address (reference)** remains the same. React thinks the state hasn't changed, and the component **will not re-render**, leading to a stale UI.
  * By using immutable methods (like `slice()`, `map()`, `filter()`, or the spread operator `...`), you generate a **new array reference**, which signals React to re-render.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Debugging and Predictability:&lt;/strong&gt; Mutating state can lead to hard-to-track bugs and makes time-travel debugging difficult. Immutable updates ensure that your previous state is always preserved, making the data flow predictable.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Immutable Alternative
&lt;/h2&gt;

&lt;p&gt;Instead of using &lt;code&gt;splice()&lt;/code&gt;, which modifies the original array, the blog post you shared correctly uses the &lt;strong&gt;spread operator (&lt;code&gt;...&lt;/code&gt;)&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;slice()&lt;/code&gt;&lt;/strong&gt; to achieve the same result immutably:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The splice() operation (DO NOT USE FOR REACT STATE)&lt;/span&gt;
&lt;span class="c1"&gt;// const oldTasks = [task1, task2, task3];&lt;/span&gt;
&lt;span class="c1"&gt;// oldTasks.splice(index, 1, updatedTask); // Mutates oldTasks&lt;/span&gt;

&lt;span class="c1"&gt;// The IMMUTABLE approach using slice() and the spread operator (Recommended)&lt;/span&gt;
&lt;span class="nf"&gt;setTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevTasks&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;prevTasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// Items before the target&lt;/span&gt;
    &lt;span class="nx"&gt;updatedTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                  &lt;span class="c1"&gt;// The new item&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;prevTasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&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="c1"&gt;// Items after the target&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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