<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Devansh Prajapati</title>
    <description>The latest articles on Forem by Devansh Prajapati (@devansh_prajapati_c7997a0).</description>
    <link>https://forem.com/devansh_prajapati_c7997a0</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%2F2046032%2F3ebfc5f1-abe9-428c-8729-b479738766cf.jpg</url>
      <title>Forem: Devansh Prajapati</title>
      <link>https://forem.com/devansh_prajapati_c7997a0</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/devansh_prajapati_c7997a0"/>
    <language>en</language>
    <item>
      <title>Engineering Scalable Forms: Decoupling Logic with RHF and Next.js App Router</title>
      <dc:creator>Devansh Prajapati</dc:creator>
      <pubDate>Sat, 04 Apr 2026 18:06:19 +0000</pubDate>
      <link>https://forem.com/devansh_prajapati_c7997a0/engineering-scalable-forms-decoupling-logic-with-rhf-and-nextjs-app-router-4h8a</link>
      <guid>https://forem.com/devansh_prajapati_c7997a0/engineering-scalable-forms-decoupling-logic-with-rhf-and-nextjs-app-router-4h8a</guid>
      <description>&lt;h2&gt;
  
  
  Introduction:
&lt;/h2&gt;

&lt;p&gt;Implementing a simple and single page using react-hook-form is very easy and we do it quite often in our applications. But it fails when it comes to modern web architecture and business logic. Large single-page forms aren't just "unattractive"; they are difficult to validate, hard to debug, and overwhelming for the user. &lt;/p&gt;

&lt;p&gt;Transitioning to a Multi-Step Wizard in Next.js introduces a unique architectural challenge: State Persistence across Route Transitions. We will implement a scalable pattern that manages state transition and validation across the Next.js App Router using &lt;code&gt;FormProvider&lt;/code&gt;, &lt;code&gt;useFromContext&lt;/code&gt; and &lt;code&gt;useFieldArray&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 1: Implementing Contextual Injection and Static Domains
&lt;/h2&gt;

&lt;p&gt;RHF utilizes the &lt;code&gt;FormProvider&lt;/code&gt; pattern to wrap component trees in a shared context. This decouples nested UI elements from the parent form's implementation details, allowing deep child components to consume form methods via &lt;code&gt;useFormContext&lt;/code&gt; without polluting the intermediate component props.&lt;/p&gt;

&lt;p&gt;To implement &lt;code&gt;FormProvider&lt;/code&gt;, initialize the form using &lt;code&gt;useForm&lt;/code&gt; and spread the resulting methods onto the provider. This establishes a shared context that allows nested components to access form state via&lt;code&gt;useFormContext&lt;/code&gt; without manual prop drilling.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useForm&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;exampleSchema&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;resolver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;zodResolver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;exampleSchema&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;defaultValues&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormProvider&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;methods&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;form&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onSubmit&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="cm"&gt;/* Rest of the Code... */&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;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="nc"&gt;FormProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Take a look at the “Dynamic Job Application Portal” Example:
&lt;/h3&gt;

&lt;p&gt;/components/job-form&lt;br&gt;
├── index.tsx              // The "Parent" (FormProvider lives here)&lt;br&gt;
├── PersonalInfo.tsx       // Child 1 (Simple inputs)&lt;br&gt;
├── ExperienceSection.tsx  // Child 2 (useFieldArray lives here)&lt;br&gt;
├── SkillPicker.tsx        // Child 3 (Controller &amp;amp; useWatch live here)&lt;br&gt;
└── SubmitButton.tsx       // Child 4 (Validation check)&lt;/p&gt;
&lt;h3&gt;
  
  
  Type Definitions:
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;JobFormValues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;personalInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;firstName&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;lastName&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;email&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="p"&gt;};&lt;/span&gt;
  &lt;span class="nl"&gt;experience&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;company&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;role&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;years&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="p"&gt;}[];&lt;/span&gt; 
  &lt;span class="nl"&gt;skills&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;jobCategory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;developer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;designer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&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;// Used for conditional logic&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;

&lt;h3&gt;
  
  
  Initializing React-Hook-Form
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// index.tsx&lt;/span&gt;


&lt;span class="c1"&gt;//crucial for use hooks&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useForm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FormProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-hook-form&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Optional: If using Zod for validation&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;zodResolver&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@hookform/resolvers/zod&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="c1"&gt;//  Default Values for the form, ensuring all fields are initialized properly&lt;/span&gt;


&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;defaultValues&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JobFormValues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;personalInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;firstName&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="na"&gt;lastName&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="na"&gt;email&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="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;experience&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="na"&gt;company&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="na"&gt;role&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="na"&gt;years&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;// Starts with one empty row&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;skills&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;jobCategory&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="p"&gt;};&lt;/span&gt;


&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;JobApplicationForm&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;methods&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useForm&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;JobFormValues&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;// resolver: zodResolver // You can define resolver for type safety&lt;/span&gt;
    &lt;span class="nx"&gt;defaultValues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;onBlur&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="p"&gt;});&lt;/span&gt;


  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormProvider&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;methods&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;form&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;                   &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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="cm"&gt;/* Child components here */&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;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="nc"&gt;FormProvider&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;h3&gt;
  
  
  useFormContext
&lt;/h3&gt;

&lt;p&gt;RHF provides the useFormContext method that allows nested components to access the form's internal state and methods without receiving them through props . This decouples nested UI elements from the parent form's implementation details, allowing deep child components to consume form methods via useFormContext without polluting the intermediate component props.&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useFormContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-hook-form&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;




&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PersonalInfo&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 can now access the form context, including register and errors, without prop drilling&lt;/span&gt;


   &lt;span class="c1"&gt;// de-structure register and formState&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;register&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useFormContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;exampleSchema&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Initializing useFormContext
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// PersonalInfo.tsx&lt;/span&gt;


&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useFormContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-hook-form&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;JobFormValues&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Import the type for safety&lt;/span&gt;


&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PersonalInfo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// You got this type of return form useFormContext&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/*
      {
  control: { ... },         // The internal engine
  register: ƒ (),           // Function to hook up inputs
  handleSubmit: ƒ (),       // Function to wrap submission
  watch: ƒ (),              // Function to observe changes
  formState: {              // The "Health" of the form
    errors: {
      personalInfo: { firstName: { message: "Required" } }
    },
    isDirty: true,
    isValid: false,
    isSubmitting: false
  },
  setValue: ƒ (),           // Update data programmatically
  getValues: ƒ (),          // Read data silently
  reset: ƒ (),              // Go back to start
  …
}
 */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;


  &lt;span class="c1"&gt;// 1. Pluck only what we need from the useFormContext&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;register&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useFormContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;JobFormValues&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;


  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"space-y-4 p-4 border rounded-lg bg-gray-50"&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="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-xl font-bold"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Personal Information&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"grid grid-cols-2 gap-4"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* 2. Using Nested Paths: "parent.child" */&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="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col"&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;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;First Name&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&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="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;personalInfo.firstName&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;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Jane"&lt;/span&gt;
            &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"border p-2 rounded"&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;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;personalInfo&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-red-500 text-sm"&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;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;personalInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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;span&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col"&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;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Email Address&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&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="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;personalInfo.email&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;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;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"jane@example.com"&lt;/span&gt;
            &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"border p-2 rounded"&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;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;personalInfo&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-red-500 text-sm"&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;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;personalInfo&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;message&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;span&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;&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;section&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;Beyond avoiding prop drilling, useFormContext grants components functional autonomy. By using this hook, a component like PersonalInfo becomes a standalone unit. You can move it across different steps of a wizard or into different layouts without modifying the component’s internal logic, as long as it remains within a FormProvider.&lt;/p&gt;

&lt;p&gt;Note: Crucially, because FormProvider and useFormContext rely on React Context, these files must include the "use client" directive. This marks the boundary between your static Server Components and your interactive form logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 2: Orchestrating Dynamic Collections with useFieldArray
&lt;/h2&gt;

&lt;p&gt;While simple inputs are easy to manage, real-world forms often require users to add, remove, or reorder lists of data—such as work history or educational background. In React Hook Form, we handle this through the useFieldArray hook.&lt;/p&gt;

&lt;p&gt;This hook provides a specialized set of methods (append, remove, move, insert) designed to manipulate arrays within your form state without losing focus or triggering unnecessary global re-renders.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initialize useFieldArray:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useFormContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useFieldArray&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-hook-form&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ExperienceSection&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;control&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useForm&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;exampleSchema&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;resolver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;zodResolver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;exampleSchema&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;defaultValues&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;append&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;remove&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useFieldArray&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;experience&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In React Hook Form, most inputs are uncontrolled (they use refs (When we do …register() we destructure the ref of that particular input field)). However, complex components like useFieldArray or Controller need a way to talk to the internal state of the library to stay in sync.&lt;/p&gt;

&lt;p&gt;The control object contains the internal logic, refs, and state subscribers for the entire form.&lt;br&gt;
Standard HTML inputs can use the register method. But dynamic arrays and custom UI components (like a Material UI slider) don't have a standard "ref" that RHF can easily grab.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
The control acts as the bridge. It provides the internal methods necessary to register these complex fields into the main form state.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ExperienceSection.tsx&lt;/span&gt;


&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useFormContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useFieldArray&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-hook-form&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;JobFormValues&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ExperienceSection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


&lt;span class="c1"&gt;//useFormContext also contains the control that we can use to register our array fields to the form&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;control&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useFormContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;JobFormValues&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;// Connecting to the "experience" array in our defaultValues&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;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;append&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;remove&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useFieldArray&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;control&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;experience&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;


  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="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;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"space-y-6 p-4 border rounded-lg"&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="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex justify-between items-center"&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="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-xl font-bold"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Work Experience&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&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;"button"&lt;/span&gt;


&lt;span class="c1"&gt;// Add blank field of array element to the array&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;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;company&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="na"&gt;role&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="na"&gt;years&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="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"bg-green-600 text-white px-3 py-1 rounded text-sm"&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          + Add Job
        &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="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;fields&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;field&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="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;field&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;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"grid grid-cols-3 gap-4 p-4 border-b relative"&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="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`experience.&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="s2"&gt;.company`&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Company"&lt;/span&gt;
            &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"border p-2 rounded"&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="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`experience.&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="s2"&gt;.role`&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Role"&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="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`experience.&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="s2"&gt;.years`&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;valueAsNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&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;"number"&lt;/span&gt;
            &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Years"&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;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;
&lt;span class="c1"&gt;// Remove the particular element from the array &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;remove&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="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-red-500 absolute right-0 top-0"&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="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="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="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;


&lt;p&gt;If you have 10 items in your "Experience" list and you click "Delete" on one, RHF needs to know exactly which index to remove and how to shift the remaining data.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The control object manages this calculation behind the scenes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It ensures that only the ExperienceSection re-renders, while the rest of your form (like PersonalInfo) stays perfectly still. This is how RHF maintains high performance in large forms.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  The Mechanics of Dynamic Mapping: experience.${index}.years
&lt;/h3&gt;

&lt;p&gt;In a standard input, you might register a field simply as "firstName". However, when dealing with dynamic arrays, we use Object Path Notation. This string is the precise "GPS coordinate" for a piece of data within your form's state tree.&lt;/p&gt;
&lt;h3&gt;
  
  
  Breaking Down the Path
&lt;/h3&gt;

&lt;p&gt;Think of your form data as a JSON object. The string &lt;code&gt;experience.${index}.years&lt;/code&gt; tells RHF exactly where to perform the update:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;experience: Identifies the top-level array defined in your defaultValues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;.${index}: The dynamic pointer. Whether the index is 0, 1, or 2, it tells RHF which specific object in the list is being modified.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;.years: The specific key (property) within that nested object.&lt;br&gt;
The Result: When a user types "5" into the second row of your form, RHF internally maps that value to: state.experience[1].years = 5.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  The valueAsNumber Transformation
&lt;/h3&gt;

&lt;p&gt;Since the years field is defined as a number in our TypeScript schema, always remember that HTML inputs return strings by default. To keep your data clean, use the valueAsNumber option:&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="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;"number"&lt;/span&gt;
  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`experience.&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="s2"&gt;.years`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;valueAsNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This ensures that your onSubmit receives the integer 5 instead of the string "5", keeping your API payloads type-safe.&lt;/p&gt;

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

&lt;p&gt;By shifting from a monolithic form structure to a decoupled architecture using FormProvider and useFieldArray, we’ve achieved three critical engineering goals:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Maintainability: Our parent component remains lean, acting only as an orchestrator while individual "domains" (Personal Info, Experience) manage their own UI logic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Performance: By leveraging the control object, we ensure that updates to a single item in a dynamic list don't trigger expensive re-renders across the entire application.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;3.&lt;br&gt;
Scalability: This pattern is "future-proof." Whether you need to add five more sections or transition to a multi-step wizard, the underlying logic of using useFormContext and nested paths remains the same.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>nextjs</category>
      <category>react</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Reverse Linked List</title>
      <dc:creator>Devansh Prajapati</dc:creator>
      <pubDate>Fri, 27 Feb 2026 16:38:33 +0000</pubDate>
      <link>https://forem.com/devansh_prajapati_c7997a0/reverse-linked-list-15m5</link>
      <guid>https://forem.com/devansh_prajapati_c7997a0/reverse-linked-list-15m5</guid>
      <description>&lt;p&gt;Reverse a Singly Linked List Objective :-&lt;br&gt;
Given the head of a singly linked list, reverse the list so that:&lt;br&gt;
The first node becomes the last&lt;/p&gt;

&lt;p&gt;The last node becomes the first&lt;/p&gt;

&lt;p&gt;All next pointers are reversed&lt;/p&gt;

&lt;p&gt;The operation is done in-place&lt;/p&gt;

&lt;p&gt;Return the new head of the reversed list.&lt;br&gt;
Understanding the Problem&lt;br&gt;
A singly linked list is a sequence of nodes where each node contains:&lt;br&gt;
A value&lt;/p&gt;

&lt;p&gt;A reference to the next node&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
1 → 2 → 3 → 4 → null&lt;br&gt;
After reversing:&lt;br&gt;
4 → 3 → 2 → 1 → null&lt;/p&gt;

&lt;p&gt;Intuition&lt;br&gt;
Here is how the linked list looks like.&lt;/p&gt;

&lt;p&gt;We are given a “head”. Which is pointing to the first node. (Node stores the value and the address to the next node.)&lt;/p&gt;

&lt;p&gt;So, What we can do here is if we store the next node’s address to the previous one then we can reverse the Linked List.&lt;/p&gt;

&lt;p&gt;In Linked List each node points to the next node so we traverse in the List and swap the address to pointing backward then maybe we reverse the LL.&lt;/p&gt;

&lt;p&gt;Let’s Try…&lt;/p&gt;

&lt;p&gt;So we required two pointers that help us to do that. Let’s take “previous” and “current” two pointers to help us.&lt;/p&gt;

&lt;p&gt;Now if you think we can assign previous to the head and current to the next of head then just we have to swap the address but be careful first store the current.next into temp node so you can go to the next address otherwise the next will be gone.&lt;br&gt;
Approach&lt;br&gt;
Here how each steps looks like:&lt;br&gt;
Step 1: &lt;/p&gt;

&lt;p&gt;Prev = 100, curr = 200.&lt;br&gt;
temp = curr.next (300)  //store the next of current&lt;br&gt;
curr.next = prev (100)   //store the previous address to the current’s next.&lt;br&gt;
prev = curr (200)   // move prev to the current &lt;br&gt;
curr = temp (300) //move the current to the next address.&lt;/p&gt;

&lt;p&gt;Step 2:&lt;/p&gt;

&lt;p&gt;Prev = 200, curr = 300.&lt;br&gt;
temp = curr.next (400)  //store the next of current&lt;br&gt;
curr.next = prev (200)   //store the previous address to the current’s next.&lt;br&gt;
prev = curr (300)   // move prev to the current &lt;br&gt;
curr = temp (400) //move the current to the next address.&lt;/p&gt;

&lt;p&gt;Step 3:&lt;/p&gt;

&lt;p&gt;Prev = 300, curr = 400.&lt;br&gt;
temp = curr.next (null)  //store the next of current&lt;br&gt;
curr.next = prev (300)   //store the previous address to the current’s next.&lt;br&gt;
prev = curr (400)   // move prev to the current &lt;br&gt;
curr = temp (null) //move the current to the next address.&lt;/p&gt;

&lt;p&gt;Step 4:&lt;/p&gt;

&lt;p&gt;At Last, Curr stores the null and prev is on the last Node.&lt;/p&gt;

&lt;p&gt;head.next = curr (null)&lt;br&gt;
head = prev;&lt;/p&gt;

&lt;p&gt;Final Output: &lt;/p&gt;

&lt;p&gt;But there are some flows in this approach: what if the head or next of head is null? Also we will update the head node’s address at the end. That also makes it a more complicated approach it works fine although if you just handle the null pointer cases.&lt;/p&gt;

&lt;p&gt;But if we take the current as head and prev as null and follow the same logic that is more appropriate and more intuitive. &lt;br&gt;
Code Solution: &lt;/p&gt;

&lt;p&gt;void reverseLL() {&lt;br&gt;
   LinkedNode prev = null;&lt;br&gt;
   LinkedNode current = head;&lt;/p&gt;

&lt;p&gt;while (current != null){&lt;br&gt;
       LinkedNode next = current.next; // store the current node's next address&lt;br&gt;
       current.next = prev; // now store the previous address to the current node's address&lt;br&gt;
       prev = current; // update the previous with current one&lt;br&gt;
       current = next; // move current to the next location&lt;br&gt;
   }&lt;/p&gt;

&lt;p&gt;//At the end Prev pointing to the last node&lt;br&gt;
   head = prev;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Initial State Before Loop:&lt;br&gt;
Variable&lt;br&gt;
Value&lt;br&gt;
prev&lt;br&gt;
null&lt;br&gt;
current&lt;br&gt;
10&lt;br&gt;
head&lt;br&gt;
10&lt;/p&gt;

&lt;p&gt;Iteration 1&lt;br&gt;
Step 1&lt;br&gt;
next = current.next → 20&lt;br&gt;
Step 2&lt;br&gt;
current.next = prev&lt;br&gt;
 10 → null&lt;br&gt;
Step 3&lt;br&gt;
prev = current → 10&lt;br&gt;
Step 4&lt;br&gt;
current = next → 20&lt;/p&gt;

&lt;p&gt;State After Iteration 1&lt;br&gt;
Reversed part:&lt;br&gt;
10 → null&lt;br&gt;
Remaining:&lt;br&gt;
20 → 30 → 40 → null&lt;br&gt;
prev&lt;br&gt;
current&lt;br&gt;
next&lt;br&gt;
  10&lt;br&gt;
      20&lt;br&gt;
20&lt;/p&gt;

&lt;p&gt;Iteration 2&lt;br&gt;
Step 1&lt;br&gt;
next = 30&lt;br&gt;
Step 2&lt;br&gt;
20.next = 10&lt;br&gt;
Step 3&lt;br&gt;
prev = 20&lt;br&gt;
Step 4&lt;br&gt;
current = 30&lt;/p&gt;

&lt;p&gt;State After Iteration 2&lt;br&gt;
Reversed part:&lt;br&gt;
20 → 10 → null&lt;br&gt;
Remaining:&lt;br&gt;
30 → 40 → null&lt;br&gt;
prev&lt;br&gt;
current&lt;br&gt;
20&lt;br&gt;
30&lt;/p&gt;

&lt;p&gt;Iteration 3&lt;br&gt;
Step 1&lt;br&gt;
next = 40&lt;br&gt;
Step 2&lt;br&gt;
30.next = 20&lt;br&gt;
Step 3&lt;br&gt;
prev = 30&lt;br&gt;
Step 4&lt;br&gt;
current = 40&lt;/p&gt;

&lt;p&gt;State After Iteration 3&lt;br&gt;
Reversed part:&lt;br&gt;
30 → 20 → 10 → null&lt;br&gt;
Remaining:&lt;br&gt;
40 → null&lt;br&gt;
prev&lt;br&gt;
current&lt;br&gt;
30&lt;br&gt;
40&lt;/p&gt;

&lt;p&gt;Iteration 4&lt;br&gt;
Step 1&lt;br&gt;
next = null&lt;br&gt;
Step 2&lt;br&gt;
40.next = 30&lt;br&gt;
Step 3&lt;br&gt;
prev = 40&lt;br&gt;
Step 4&lt;br&gt;
current = null&lt;/p&gt;

&lt;p&gt;State After Iteration 4&lt;br&gt;
Reversed part:&lt;br&gt;
40 → 30 → 20 → 10 → null&lt;br&gt;
Remaining:&lt;br&gt;
null&lt;br&gt;
prev&lt;br&gt;
current&lt;br&gt;
40&lt;br&gt;
null&lt;/p&gt;

&lt;p&gt;Loop Ends&lt;br&gt;
Now:&lt;br&gt;
head = prev&lt;br&gt;
So:&lt;br&gt;
head = 40&lt;/p&gt;

&lt;p&gt;Final Reversed List&lt;br&gt;
40 → 30 → 20 → 10 → null&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>beginners</category>
      <category>computerscience</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Stop Using Extra Arrays: Mastering the Two-Pointer Approach</title>
      <dc:creator>Devansh Prajapati</dc:creator>
      <pubDate>Sun, 25 Jan 2026 09:56:55 +0000</pubDate>
      <link>https://forem.com/devansh_prajapati_c7997a0/stop-using-extra-arrays-mastering-the-two-pointer-approach-3nkd</link>
      <guid>https://forem.com/devansh_prajapati_c7997a0/stop-using-extra-arrays-mastering-the-two-pointer-approach-3nkd</guid>
      <description>&lt;p&gt;In a two pointer approach we use two pointers which are pointing at two different or sometimes same locations in an array. For problems like move targeted element where we move target element at the front or end of the array or problem like remove duplicates where in sorted or unsorted array we remove the duplicate elements or move those elements at the end of the array can be approached or solved by the two pointer approach where the time complexity can be 0(n).&lt;/p&gt;

&lt;p&gt;Let’s learn a two pointer approach by one example:-  Remove duplicates from an array.&lt;/p&gt;

&lt;p&gt;Problem statement:&lt;br&gt;
Given an integer array nums sorted in non-decreasing order, remove the duplicates in-place such that each unique element appears only once. The relative order of the elements should be kept the same. [this is the problem from leetcode #26]&lt;/p&gt;

&lt;p&gt;Consider the number of unique elements in nums to be k​​​​​​​​​​​​​​. After removing duplicates, return the number of unique elements k.&lt;/p&gt;

&lt;p&gt;example:-&lt;br&gt;
Input: nums = [1,1,2]&lt;br&gt;
Output: 2, nums = [1,2,_]&lt;/p&gt;

&lt;p&gt;Input: nums = [0,0,1,1,1,2,2,3,3,4]&lt;br&gt;
Output: 5, nums = [0,1,2,3,4,&lt;em&gt;,&lt;/em&gt;,&lt;em&gt;,&lt;/em&gt;,_]&lt;/p&gt;

&lt;p&gt;The standard approach would be to loop through an array and add unique elements to a new array. But in that case time complexity remains O(n) but space complexity would grow to the size of an array O(n) too. In small arrays like 100 or even 1000 entries it won’t be much difference but what if the array size is in billion? Takes too much extra space right? Here is where the two pointer approach comes in.&lt;/p&gt;

&lt;p&gt;Lets see How would we solve this problem with a two pointer approach?&lt;/p&gt;

&lt;p&gt;I solved this problem using the 'Paper-First' method—a part of my daily routine to ensure my logic is peaceful and precise before I ever touch the keyboard.&lt;/p&gt;

&lt;p&gt;Solution:&lt;/p&gt;

&lt;p&gt;var removeDuplicates = function(nums) {&lt;br&gt;
    if (nums.length === 0) return 0;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// We start at 1 because the first element is always unique
let insertIndex = 1;


for (let i = 1; i &amp;lt; nums.length; i++) {
    // If current element is different from the previous unique one
    if (nums[i] !== nums[insertIndex - 1]) {
        nums[insertIndex] = nums[i];
        insertIndex++;
    }
}


return insertIndex;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;};&lt;/p&gt;

&lt;p&gt;Here, &lt;/p&gt;

&lt;p&gt;Step-1: if (nums.length === 0) return 0; Handling the Edge Case.&lt;br&gt;
The first edge case handles the empty array. If an array has no element then we return zero cause there is nothing to perform on.&lt;/p&gt;

&lt;p&gt;Step-2: let insertIndex = 1;&lt;br&gt;
Variable declaration: In our case this acts as a pointer (1st pointer) that we use to point to the desired index to perform swap operation.&lt;/p&gt;

&lt;p&gt;Step-3: for (let i = 1; i &amp;lt; nums.length; i++) { … }; loop&lt;br&gt;
In step - 3 we loop through an array and do changes in this array to save the extra space.&lt;br&gt;
if (nums[i] !== nums[insertIndex - 1]) {&lt;br&gt;
            nums[insertIndex] = nums[i];&lt;br&gt;
            insertIndex++;&lt;br&gt;
        }&lt;/p&gt;

&lt;p&gt;This is the most important part of the code. Where we put our logic. We check everytime that if the nums&lt;a href="https://dev.toarray%20element%20at%20the%20index%20of%20i"&gt;i&lt;/a&gt; is equal to the last element of insertIndex (-1)? &lt;br&gt;
Without nums[insertIndex - 1] would throw an error on an empty array. Because we started the index from 1. &lt;/p&gt;

&lt;p&gt;Example: - nums = [] // length is 0&lt;br&gt;
So checking nums[insertIndex] = 1 array index out of Bound error.&lt;/p&gt;

&lt;p&gt;If not then this is the unique element so we add the new element at the index of insertIndex. And increment the insertIndex so we add the next unique element at the next place of this operation.&lt;/p&gt;

&lt;p&gt;Step-4: Return the last updated index: insterIndex &lt;br&gt;
At the end we return the last updated index insertIndex which is pointing to the next point of the last added element.&lt;/p&gt;

&lt;p&gt;Dry Run: &lt;/p&gt;

&lt;p&gt;We can better understand this by dry running the code on the example array.&lt;/p&gt;

&lt;p&gt;Example: [ 0, 0, 1, 1, 2 ]&lt;/p&gt;

&lt;p&gt;Step&lt;br&gt;
i (Explorer)&lt;br&gt;
nums[i]&lt;br&gt;
nums[insertIndex-1]&lt;br&gt;
Comparison&lt;br&gt;
Action&lt;br&gt;
Array State&lt;br&gt;
Start&lt;br&gt;
1&lt;br&gt;
0&lt;br&gt;
0 (at index 0)&lt;br&gt;
0 !== 0? No&lt;br&gt;
Skip&lt;br&gt;
[0, 0, 1, 1, 2]&lt;br&gt;
Iter 1&lt;br&gt;
2&lt;br&gt;
1&lt;br&gt;
0 (at index 0)&lt;br&gt;
1 !== 0? Yes&lt;br&gt;
nums[1] = 1; insertIndex++&lt;br&gt;
[0, 1, 1, 1, 2]&lt;br&gt;
Iter 2&lt;br&gt;
3&lt;br&gt;
1&lt;br&gt;
1 (at index 1)&lt;br&gt;
1 !== 1? No&lt;br&gt;
Skip&lt;br&gt;
[0, 1, 1, 1, 2]&lt;br&gt;
Iter 3&lt;br&gt;
4&lt;br&gt;
2&lt;br&gt;
1 (at index 1)&lt;br&gt;
2 !== 1? Yes&lt;br&gt;
nums[2] = 2; insertIndex++&lt;br&gt;
[0, 1, 2, 1, 2]&lt;/p&gt;

&lt;p&gt;Key Takeaway: &lt;br&gt;
Time Complexity: O(n)&lt;br&gt;
Space Complexity: O(1)&lt;br&gt;
Best for: In-place modifications of sorted arrays.&lt;/p&gt;

&lt;p&gt;Conclusion&lt;br&gt;
So, the Two pointer Approach is a classic and easy to implement algorithm. In three steps we can implement this. 1st is return on an empty array, 2nd is defining the variable (pointer to 1 or 0 depending on the problem) 3rd would be to loop through it and check if the current element is unique to the last updated element? 4th return the last updated variable. simple and effective.&lt;/p&gt;

&lt;p&gt;To check your knowledge? The Problem: Given an array of integers, move all the zeroes to the end of it while maintaining the relative order of the non-zero elements.&lt;br&gt;
Example: [0, 1, 0, 3, 12] -&amp;gt; [1, 3, 12, 0, 0]&lt;br&gt;
Constraint: You must do this in-place without making a copy of the array.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>interview</category>
      <category>leetcode</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
