<?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: Vatsal Acharya</title>
    <description>The latest articles on DEV Community by Vatsal Acharya (@vatsalacharya).</description>
    <link>https://dev.to/vatsalacharya</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%2F3337540%2F52540516-6a2d-4275-88f2-9fbd5a0a2415.jpg</url>
      <title>DEV Community: Vatsal Acharya</title>
      <link>https://dev.to/vatsalacharya</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vatsalacharya"/>
    <language>en</language>
    <item>
      <title>Understanding Core React Hooks with Practical Examples</title>
      <dc:creator>Vatsal Acharya</dc:creator>
      <pubDate>Tue, 10 Mar 2026 08:46:16 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/understanding-core-react-hooks-with-practical-examples-1okn</link>
      <guid>https://dev.to/addwebsolutionpvtltd/understanding-core-react-hooks-with-practical-examples-1okn</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;“React Hooks turned complex class components into simple, reusable functions.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;React Hooks replaced class components as the standard way to write React.&lt;/li&gt;
&lt;li&gt;useState, useEffect, and useContext are used in almost every production React app.&lt;/li&gt;
&lt;li&gt;Performance hooks like useMemo, useCallback, and useTransition prevent unnecessary re-renders.&lt;/li&gt;
&lt;li&gt;useReducer is better than useState for complex state logic.&lt;/li&gt;
&lt;li&gt;Custom hooks allow reusable business logic across components.&lt;/li&gt;
&lt;li&gt;React 18 introduced concurrent features like useTransition and useDeferredValue.&lt;/li&gt;
&lt;li&gt;Hooks must follow the Rules of Hooks to avoid bugs and performance issues.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction to React Hooks&lt;/li&gt;
&lt;li&gt;Quick Reference - All Hooks&lt;/li&gt;
&lt;li&gt;State Management Hooks&lt;/li&gt;
&lt;li&gt;Context Hook&lt;/li&gt;
&lt;li&gt;Effect Hooks&lt;/li&gt;
&lt;li&gt;Ref Hooks&lt;/li&gt;
&lt;li&gt;Performance Hooks&lt;/li&gt;
&lt;li&gt;React 18 - Transition Hooks&lt;/li&gt;
&lt;li&gt;Utility Hooks&lt;/li&gt;
&lt;li&gt;React 19 - Form and Optimistic Hooks&lt;/li&gt;
&lt;li&gt;Custom Hooks&lt;/li&gt;
&lt;li&gt;Rules of Hooks&lt;/li&gt;
&lt;li&gt;Stats &lt;/li&gt;
&lt;li&gt;Interesting Facts&lt;/li&gt;
&lt;li&gt;FAQ's&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Introduction to React Hooks
&lt;/h2&gt;

&lt;p&gt;React Hooks were introduced in React 16.8 (released February 2019) and fundamentally transformed how developers build components. Before hooks, building stateful or interactive React components required writing class components with lifecycle methods like componentDidMount, componentDidUpdate, and componentWillUnmount - verbose, often confusing, and difficult to share logic between components.&lt;br&gt;
Hooks change all of that. They let you use state, side effects, context, and other React features directly inside plain JavaScript functions - no class required.&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%2Fv95tkgpckmhxucann3wj.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%2Fv95tkgpckmhxucann3wj.png" alt=" " width="628" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is how each major React version expanded the hooks system:&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%2F9c7c7dbxaqf5nl389ma3.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%2F9c7c7dbxaqf5nl389ma3.png" alt=" " width="631" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The real power lies not just in knowing hooks, but in knowing when to use them, when not to, and how to combine them effectively.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick Reference - All Hooks at a Glance&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%2Ftmk5z03mfoqf9ydp445u.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%2Ftmk5z03mfoqf9ydp445u.png" alt=" " width="634" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Hooks are not just features in React - they are the foundation of modern React development.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  State Management Hooks
&lt;/h2&gt;

&lt;p&gt;These hooks store and manage data inside your component. Start here - you will use them in every React app you build.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. useState - Local Component State&lt;/strong&gt;&lt;br&gt;
The most fundamental hook. Use it to store any simple value that should trigger a re-render when it changes - booleans, strings, numbers, arrays, or objects.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&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="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;Clicked&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;times&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Real-Life Example: Light Switch&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;LightSwitch&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;isOn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsOn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setIsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isOn&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isOn&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Light ON&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;Light OFF&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Common practical uses:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Form inputs and controlled components&lt;/li&gt;
&lt;li&gt;Toggle dark/light theme&lt;/li&gt;
&lt;li&gt;Loading and error state management&lt;/li&gt;
&lt;li&gt;Modal open/close state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. useReducer - Complex State Logic&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Think of useReducer as mini-Redux inside a single component. When state logic becomes complex or involves multiple related values that change together, reach for useReducer instead of stacking multiple useStates.&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;reducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;increment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;decrement&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reset&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;count&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="nl"&gt;default&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;state&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;function&lt;/span&gt; &lt;span class="nf"&gt;Counter&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;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;count&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;increment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;+&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;decrement&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;-&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reset&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Reset&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use useReducer over useState:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State logic involves multiple sub-values&lt;/li&gt;
&lt;li&gt;The next state depends on the previous one in complex ways&lt;/li&gt;
&lt;li&gt;Multi-step forms with validation&lt;/li&gt;
&lt;li&gt;Shopping cart logic with add, remove, and update quantity&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Context Hook
&lt;/h2&gt;

&lt;p&gt;Context lets you share data globally across your component tree without passing props through every level (prop drilling).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. useContext - Global State Without Redux&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useContext&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ThemeContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;light&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Button&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;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThemeContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;theme&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;Click&lt;/span&gt; &lt;span class="nx"&gt;me&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ThemeContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ThemeContext.Provider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Perfect for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication - storing the logged-in user globally&lt;/li&gt;
&lt;li&gt;Theme management - dark/light mode across the entire app&lt;/li&gt;
&lt;li&gt;Language and i18n switching&lt;/li&gt;
&lt;li&gt;App-wide notifications or toast messages
For small-to-medium apps, useContext can fully replace Redux. For very large apps with complex state interactions, consider Redux or Zustand.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Effect Hooks
&lt;/h2&gt;

&lt;p&gt;Effect hooks let you run code that interacts with things outside of React - the browser, external APIs, timers, and subscriptions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. useEffect - Side Effects After Render&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Runs after the component renders. Use it for anything that needs to happen as a consequence of rendering - API calls, subscriptions, DOM updates, and timers.&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;// Runs once on mount (empty dependency array)&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;fetchUsers&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="c1"&gt;// Runs every time 'userId' changes&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;fetchUserDetails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&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;userId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// Cleanup example -- WebSocket or timer&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;tick&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// cleanup on unmount&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Common uses:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API calls on component mount or when data changes&lt;/li&gt;
&lt;li&gt;WebSocket and real-time subscriptions&lt;/li&gt;
&lt;li&gt;Timers and intervals&lt;/li&gt;
&lt;li&gt;Updating the document title&lt;/li&gt;
&lt;li&gt;Most Common Mistake: A wrong or missing dependency array causes 
infinite re-renders. Always include every variable used inside the effect in the dependency array.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;5. useLayoutEffect - Before the Browser Paints&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Identical to useEffect, but fires synchronously after DOM mutations and before the browser paints pixels to screen. Use this when you need to measure or adjust the DOM to prevent a visible flicker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useLayoutEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&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="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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SquareBox&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;boxRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setHeight&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useLayoutEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;boxRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offsetWidth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;setHeight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// make it a perfect square&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;boxRef&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;200px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&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;Perfect&lt;/span&gt; &lt;span class="nx"&gt;Square&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use useLayoutEffect when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Measuring DOM dimensions before showing the component&lt;/li&gt;
&lt;li&gt;Preventing a visible layout flicker or jump&lt;/li&gt;
&lt;li&gt;Animating elements that need precise initial position data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;6. useInsertionEffect - For CSS Library Authors&lt;/strong&gt;&lt;br&gt;
Runs before layout and painting to inject styles into the document. This is a very low-level hook used internally by CSS-in-JS libraries like Styled-components and Emotion. You will rarely need this in application code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useInsertionEffect&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;StyledComponent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;useInsertionEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;style&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.my-class { color: black; }&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-class&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Ref Hooks
&lt;/h2&gt;

&lt;p&gt;Ref hooks let you hold a mutable value that persists between renders without triggering a re-render, and give you a way to directly access DOM nodes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. useRef - DOM Access and Persistent Values&lt;/strong&gt;&lt;br&gt;
Refs are like a box where you can put any value. Changing a ref does NOT cause a re-render. Two common uses: accessing a DOM element directly, or storing a value that needs to persist across renders.&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;// Use case 1: Access DOM element&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inputRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;inputRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Focus on mount&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;inputRef&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="c1"&gt;// Use case 2: Persist value without causing re-render&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;renderCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;renderCount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Practical uses:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Programmatically focus input fields&lt;/li&gt;
&lt;li&gt;Store the previous value of a prop or state&lt;/li&gt;
&lt;li&gt;Hold a timer ID without triggering re-renders&lt;/li&gt;
&lt;li&gt;Integrate with non-React third-party DOM libraries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;8. useImperativeHandle - Expose Child Methods to Parent&lt;/strong&gt;&lt;br&gt;
Customises what a parent component can access when it uses a ref on a child. Used together with forwardRef.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;forwardRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useImperativeHandle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CustomInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;forwardRef&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inputRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;useImperativeHandle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nf"&gt;focusInput&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;inputRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nf"&gt;clearInput&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;inputRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&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="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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;inputRef&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Parent&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;inputRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CustomInput&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;inputRef&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;inputRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;focusInput&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;Focus&lt;/span&gt; &lt;span class="nx"&gt;Child&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Performance Hooks
&lt;/h2&gt;

&lt;p&gt;React re-renders components whenever state or props change. These hooks let you control exactly what gets recalculated or recreated, preventing unnecessary work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. useMemo - Memoize Expensive Calculations&lt;/strong&gt;&lt;br&gt;
Caches the result of an expensive calculation and only recomputes it when its dependencies change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useMemo&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ProductList&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;category&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;filtered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;products&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;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;category&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;products&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;category&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;filtered&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;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;p&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="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not overuse useMemo. It has its own overhead. Only add it when you have measured a real performance problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. useCallback - Memoize Function References&lt;/strong&gt;&lt;br&gt;
Returns a memoized version of a function that only changes if its dependencies change. Prevents child re-renders caused by a new function reference on every parent render.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Button clicked!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt; &lt;span class="c1"&gt;// Same function reference every render&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ChildComponent&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  React 18 Transition Hooks
&lt;/h2&gt;

&lt;p&gt;React 18 introduced concurrent rendering - the ability to work on multiple state updates simultaneously and prioritise the most important ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;11. useTransition - Non-Blocking UI Updates&lt;/strong&gt;&lt;br&gt;
Marks a state update as non-urgent so React can keep the UI responsive while processing it in the background.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useTransition&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SearchPage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;allItems&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;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setQuery&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setList&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;allItems&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;isPending&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;startTransition&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTransition&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Urgent: update input immediately&lt;/span&gt;
    &lt;span class="nf"&gt;startTransition&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;allItems&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;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
    &lt;span class="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="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isPending&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;list&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;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;12. useDeferredValue - Delay a Value Update&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Accepts a value and returns a deferred version of it. When the value changes rapidly, the deferred version lags slightly, letting the UI stay responsive.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useDeferredValue&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SearchList&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;items&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;search&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSearch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deferredSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useDeferredValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;search&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;filtered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&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="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deferredSearch&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;filtered&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;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Utility Hooks
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;13. useId - Unique Accessible IDs&lt;/strong&gt;&lt;br&gt;
Generates a stable unique ID consistent between server and client rendering. Essential for accessibility - correctly linking HTML labels to their inputs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Small hooks, powerful logic - that’s the beauty of modern React.”&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useId&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;FormField&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;label&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;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useId&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="nx"&gt;htmlFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;14. useSyncExternalStore - Subscribe to External Data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The correct way to subscribe to external data sources like browser APIs or Redux store.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useSyncExternalStore&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resize&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resize&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;WindowWidth&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;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSyncExternalStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerWidth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Window&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="nx"&gt;px&lt;/span&gt; &lt;span class="nx"&gt;wide&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;15. useDebugValue - Debug Custom Hooks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Adds a label to a custom hook that appears in React DevTools. Only useful inside custom hooks for debugging - no effect on production behaviour.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useDebugValue&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useOnlineStatus&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;isOnline&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;useDebugValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isOnline&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Online&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;Offline&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;isOnline&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;h2&gt;
  
  
  React 19 Form and Optimistic Hooks
&lt;/h2&gt;

&lt;p&gt;React 19 introduces hooks designed around server actions and forms, making form handling and optimistic UI significantly simpler.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;16. useFormStatus - Know If a Form Is Submitting&lt;/strong&gt;&lt;br&gt;
Must be used inside a component that is a child of a form element. Gives access to the parent form's submission state.&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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;useFormStatus&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-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SubmitButton&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;pending&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useFormStatus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pending&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pending&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Submitting...&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;Submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;17. useFormState - Manage Form Validation State&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Manages state that comes back from a form action - like validation errors or success messages.&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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;useFormState&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-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Name is required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&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="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyForm&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;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;formAction&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useFormState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;validateName&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formAction&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Submit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;18. useOptimistic - Instant UI Before Server Confirms&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Shows an optimistic (assumed-successful) version of the UI immediately before the server has confirmed the operation. Rolls back automatically on failure.&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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;useOptimistic&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="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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;CommentSection&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;comments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setComments&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;optimisticComments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;addOptimistic&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useOptimistic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newComment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newComment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;pending&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="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addComment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&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;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;comment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;addOptimistic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;postCommentToServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setComments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;text&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="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;addComment&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;comment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt; &lt;span class="nx"&gt;Comment&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;optimisticComments&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;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;))}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Custom Hooks
&lt;/h2&gt;

&lt;p&gt;Custom hooks let you extract and reuse stateful logic across multiple components. They are simply JavaScript functions that start with 'use' and can call other hooks.&lt;br&gt;
If you find yourself copy-pasting the same useEffect and useState pattern across components, it belongs in a custom hook.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Custom Hooks are where React truly becomes scalable and elegant.”&lt;br&gt;
&lt;strong&gt;Example 1: useFetch - Reusable Data Fetching&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&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;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setLoading&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="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;setData&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="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;url&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="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="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example 2: useDebounce - Optimised Search Input&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useDebounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&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;debouncedValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setDebouncedValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&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;setDebouncedValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timer&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;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&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;debouncedValue&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;debouncedQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useDebounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchQuery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;searchAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;debouncedQuery&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;debouncedQuery&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example 3: useToggle - Reusable Boolean Toggle&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useToggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initial&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initial&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;toggle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;prev&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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toggle&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;isOpen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useToggle&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;isDark&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toggleDark&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useToggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example 4: useAuth - Authentication State&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useContext&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useAuth&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;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AuthContext&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;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loginAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&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;logout&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="nf"&gt;setUser&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="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;token&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="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isAdmin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logout&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;h2&gt;
  
  
  Rules of Hooks
&lt;/h2&gt;

&lt;p&gt;React relies on the order in which hooks are called being stable between renders. Breaking these rules causes subtle bugs that are very hard to track down.&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%2F3424yuc8klmnu4ez09u7.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%2F3424yuc8klmnu4ez09u7.png" alt=" " width="634" height="218"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Stats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;According to the Stack Overflow Developer Survey 2023, React remains one of the most widely used web frameworks worldwide.&lt;/li&gt;
&lt;li&gt;Source: &lt;a href="https://survey.stackoverflow.co/2023/" rel="noopener noreferrer"&gt;https://survey.stackoverflow.co/2023/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;React has 200,000+ stars on GitHub, making it one of the most popular open-source libraries.&lt;/li&gt;
&lt;li&gt;Source: &lt;a href="https://github.com/facebook/react" rel="noopener noreferrer"&gt;https://github.com/facebook/react&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;According to State of JS survey, React continues to rank among the most adopted frontend frameworks.&lt;/li&gt;
&lt;li&gt;Source: &lt;a href="https://stateofjs.com/" rel="noopener noreferrer"&gt;https://stateofjs.com/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Interesting Facts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;React Hooks were proposed by Dan Abramov and Sebastian Markbåge.&lt;/li&gt;
&lt;li&gt;Hooks eliminated the need for most class components.&lt;/li&gt;
&lt;li&gt;Hooks enabled the creation of custom hooks, which allow logic reuse without higher-order components or render props.&lt;/li&gt;
&lt;li&gt;Libraries like React Query, Zustand, and TanStack Table heavily rely on hooks internally.&lt;/li&gt;
&lt;li&gt;Hooks follow strict rules because React depends on the order of hook calls to manage component state efficiently.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ's
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Are class components deprecated?&lt;/strong&gt;&lt;br&gt;
No. Class components still work in React, but modern React development almost always uses hooks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Can hooks replace Redux?&lt;/strong&gt;&lt;br&gt;
For small to medium applications, useContext+useReducer can replace Redux.&lt;br&gt;
However, large applications often benefit from dedicated state libraries like Redux, Zustand, or Jotai.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Why must hooks follow strict rules?&lt;/strong&gt;&lt;br&gt;
React internally tracks hook calls based on their order during each render.&lt;br&gt;
Calling hooks conditionally breaks this order and causes unpredictable behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Can custom hooks call other hooks?&lt;/strong&gt;&lt;br&gt;
Yes - that’s the main idea behind them.&lt;/p&gt;

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

&lt;p&gt;React Hooks fundamentally changed how developers build React applications.&lt;/p&gt;

&lt;p&gt;Instead of writing complex class components with lifecycle methods, developers can now manage state, side effects, performance optimizations, and global data using small composable functions.&lt;br&gt;
Learning when to use each hook - and when not to - is one of the most important skills for becoming a confident React developer.&lt;br&gt;
Start with the core hooks: useState, useEffect, useContext, and useRef.&lt;/p&gt;

&lt;p&gt;Once comfortable, explore advanced hooks like useMemo, useCallback, and React 18’s concurrent features.&lt;/p&gt;

&lt;p&gt;And finally, begin writing your own custom hooks - this is where React truly becomes powerful and scalable.&lt;/p&gt;

&lt;p&gt;About the Author:&lt;em&gt;Vatsal is a web developer at &lt;a href="https://www.addwebsolution.com/" rel="noopener noreferrer"&gt;AddWebSolution&lt;/a&gt;. Building web magic with Laravel, PHP, MySQL, Vue.js &amp;amp; more.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>reacthooks</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>State Management in Vue 3 for Laravel Applications (Pinia Integration)</title>
      <dc:creator>Vatsal Acharya</dc:creator>
      <pubDate>Fri, 06 Feb 2026 10:30:10 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/state-management-in-vue-3-for-laravel-applications-pinia-integration-1jkf</link>
      <guid>https://dev.to/addwebsolutionpvtltd/state-management-in-vue-3-for-laravel-applications-pinia-integration-1jkf</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;“Great applications don’t just work-they stay understandable as they grow.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Pinia is the official state management solution for Vue 3, designed to replace Vuex with a simpler and more intuitive API.&lt;/li&gt;
&lt;li&gt;Pinia integrates seamlessly with Laravel-powered APIs, making it ideal for SPA and hybrid applications.&lt;/li&gt;
&lt;li&gt;State is modular, type-safe, and easier to reason about compared to traditional global stores.&lt;/li&gt;
&lt;li&gt;Pinia simplifies complex UI logic such as authentication, permissions, carts, and dashboards.&lt;/li&gt;
&lt;li&gt;Perfect for Laravel + Vue 3 projects using Sanctum, JWT, or token-based authentication.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction to State Management in Vue 3&lt;/li&gt;
&lt;li&gt;Why Pinia Is the Preferred Choice&lt;/li&gt;
&lt;li&gt;Laravel + Vue 3 Application Architecture&lt;/li&gt;
&lt;li&gt;Statistics&lt;/li&gt;
&lt;li&gt;Core Concepts of Pinia&lt;/li&gt;
&lt;li&gt;Practical Implementation: Authentication State with Laravel&lt;/li&gt;
&lt;li&gt;Advanced Store Patterns&lt;/li&gt;
&lt;li&gt;Interesting Facts&lt;/li&gt;
&lt;li&gt;Best Practices&lt;/li&gt;
&lt;li&gt;FAQ's&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Introduction to State Management in Vue 3
&lt;/h2&gt;

&lt;p&gt;As Laravel applications increasingly adopt Vue 3 for rich, reactive frontends, managing shared state becomes a critical architectural concern. Data such as authenticated users, permissions, notifications, and UI preferences must remain consistent across multiple components and routes.&lt;/p&gt;

&lt;p&gt;Pinia was introduced to solve exactly this problem. It provides a clean, modular, and scalable approach to state management, perfectly aligned with Vue 3’s Composition API. When paired with a Laravel backend, Pinia becomes the bridge between server-side logic and frontend experience.&lt;/p&gt;

&lt;p&gt;The biggest advantage of Pinia is not just reduced boilerplate-it’s predictability. State flows in one direction, actions are explicit, and debugging becomes dramatically easier.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Good state management doesn’t make apps bigger-it makes complexity visible and manageable.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why Pinia Is the Preferred Choice
&lt;/h2&gt;

&lt;p&gt;Pinia is now the officially recommended state manager by the Vue core team. Vuex, while still supported, is no longer the future.&lt;br&gt;
Pinia improves on Vuex by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Removing mutations entirely&lt;/li&gt;
&lt;li&gt;Encouraging modular stores&lt;/li&gt;
&lt;li&gt;Supporting TypeScript by default&lt;/li&gt;
&lt;li&gt;Reducing mental overhead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Laravel developers used to service classes and repositories, Pinia feels familiar: state is centralized, actions perform logic, and getters act like computed properties.&lt;/p&gt;

&lt;h2&gt;
  
  
  Laravel + Vue 3 Application Architecture
&lt;/h2&gt;

&lt;p&gt;A typical production-ready architecture looks like this:&lt;/p&gt;

&lt;p&gt;Laravel (Backend API)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication (Sanctum / JWT)&lt;/li&gt;
&lt;li&gt;Controllers &amp;amp; Services&lt;/li&gt;
&lt;li&gt;API Resources&lt;/li&gt;
&lt;li&gt;Business rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vue 3 (Frontend SPA)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pinia Stores&lt;/li&gt;
&lt;li&gt;Vue Router&lt;/li&gt;
&lt;li&gt;Axios / Fetch layer&lt;/li&gt;
&lt;li&gt;UI Components&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Laravel handles server state (database, auth rules), while Pinia manages client state (logged-in user, UI flags, cached responses).&lt;/p&gt;

&lt;p&gt;This separation keeps both layers clean and testable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Statistics
&lt;/h2&gt;

&lt;p&gt;State Management Adoption Metrics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pinia is used in over 70% of new Vue 3 projects
Source: &lt;a href="https://stateofjs.com" rel="noopener noreferrer"&gt;https://stateofjs.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Vuex usage has declined by more than 40% since Pinia’s release
Source: &lt;a href="https://pinia.vuejs.org" rel="noopener noreferrer"&gt;https://pinia.vuejs.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Laravel + SPA architecture adoption has grown by 60% since 2022
Source: &lt;a href="https://laravel.com" rel="noopener noreferrer"&gt;https://laravel.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Pinia has over 14,000 GitHub stars, reflecting strong community trust
Source: &lt;a href="https://github.com/vuejs/pinia" rel="noopener noreferrer"&gt;https://github.com/vuejs/pinia&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pinia reduces store-related boilerplate by approximately 35–45% compared to Vuex.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Concepts of Pinia
&lt;/h2&gt;

&lt;p&gt;Pinia is built on a few simple but powerful concepts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Store&lt;/strong&gt;
A store is a container for state, actions, and getters. Each store focuses on a single domain such as authentication, orders, or notifications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State&lt;/strong&gt;
State is reactive data shared across components. It behaves like Vue’s reactive() but is globally accessible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Actions&lt;/strong&gt;
Actions handle business logic and asynchronous operations like API calls. Unlike Vuex, actions can directly modify state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Getters&lt;/strong&gt;
Getters are derived values, similar to computed properties. They keep templates clean and logic centralized.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Practical Implementation: Authentication State with Laravel
&lt;/h2&gt;

&lt;p&gt;Authentication is the most common real-world use case for Pinia in Laravel applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;&lt;br&gt;
A Vue 3 SPA consumes a Laravel API secured with Sanctum or JWT. The frontend needs to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Track logged-in user&lt;/li&gt;
&lt;li&gt;Store auth token&lt;/li&gt;
&lt;li&gt;Control access to routes&lt;/li&gt;
&lt;li&gt;Show/hide UI elements&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Auth Store Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineStore&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;pinia&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&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;axios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useAuthStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth&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;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;user&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;token&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;loading&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="na"&gt;getters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;

      &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;common&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Authorization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;

      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="nf"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
      &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;common&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Authorization&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;This store becomes the single source of truth for authentication across the app.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“When auth state is predictable, the rest of the UI becomes simple.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Advanced Store Patterns
&lt;/h2&gt;

&lt;p&gt;As applications grow, Pinia scales gracefully.&lt;/p&gt;

&lt;p&gt;Common advanced patterns include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple stores (auth, cart, permissions)&lt;/li&gt;
&lt;li&gt;Store composition (one store using another)&lt;/li&gt;
&lt;li&gt;Persisted state using localStorage&lt;/li&gt;
&lt;li&gt;Resetting state on logout&lt;/li&gt;
&lt;li&gt;Role-based UI using getters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pinia encourages small, focused stores instead of one massive global state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interesting Facts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Pinia was created by a Vue core team member and officially adopted by the framework.&lt;/li&gt;
&lt;li&gt;Pinia stores are tree-shakable, reducing bundle size.&lt;/li&gt;
&lt;li&gt;Vue DevTools natively supports Pinia without extra setup.&lt;/li&gt;
&lt;li&gt;Pinia works perfectly with SSR and Vite-based setups.&lt;/li&gt;
&lt;li&gt;Pinia supports multiple store instances for advanced scenarios like multi-tenant apps.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create one store per domain instead of a single global store. This keeps logic organized and scalable.&lt;/li&gt;
&lt;li&gt;Keep API calls inside actions, not components. This makes components simpler and easier to test.&lt;/li&gt;
&lt;li&gt;Use getters for computed logic instead of recalculating values in templates.&lt;/li&gt;
&lt;li&gt;Reset stores on logout to avoid stale or leaked data.&lt;/li&gt;
&lt;li&gt;Avoid storing sensitive data directly; let Laravel handle secrets and validation.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;“A clean store is like a clean backend service-boring in the best way.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  FAQ's
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: Is Pinia mandatory for Vue 3?&lt;/strong&gt;&lt;br&gt;
A: No, but it’s the recommended standard for shared state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Can Pinia completely replace Vuex?&lt;/strong&gt;&lt;br&gt;
A: Yes. Vue officially endorses Pinia as Vuex’s successor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Is Pinia suitable for large applications?&lt;/strong&gt;&lt;br&gt;
A: Absolutely. It scales better due to modular design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Should Laravel manage frontend state?&lt;/strong&gt;&lt;br&gt;
A: No. Laravel manages server state; Pinia manages UI state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Can Pinia be used with TypeScript?&lt;/strong&gt;&lt;br&gt;
A: Yes. Type safety is one of Pinia’s strongest features.&lt;/p&gt;

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

&lt;p&gt;Pinia represents a major evolution in how Vue applications handle state. When combined with Laravel’s robust backend capabilities, it creates a clean, scalable, and developer-friendly architecture.&lt;br&gt;
By eliminating boilerplate, simplifying async logic, and embracing modular design, Pinia allows teams to focus on features instead of fighting state complexity.&lt;/p&gt;

&lt;p&gt;For any modern Laravel + Vue 3 project-whether it’s an admin panel, SaaS dashboard, or public-facing SPA-Pinia is no longer optional. It’s the right tool for the job.&lt;/p&gt;

&lt;p&gt;About the Author:&lt;em&gt;Vatsal is a web developer at &lt;a href="//addwebsolution.com"&gt;AddWebSolution&lt;/a&gt;. Building web magic with Laravel, PHP, MySQL, Vue.js &amp;amp; more.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vue</category>
      <category>pinatachallenge</category>
      <category>vuewithlaravel</category>
      <category>modernwebdev</category>
    </item>
    <item>
      <title>Laravel Prompts: Interactive CLI Made Simple</title>
      <dc:creator>Vatsal Acharya</dc:creator>
      <pubDate>Wed, 31 Dec 2025 10:04:43 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/laravel-prompts-interactive-cli-made-simple-2n6</link>
      <guid>https://dev.to/addwebsolutionpvtltd/laravel-prompts-interactive-cli-made-simple-2n6</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;"Laravel Prompts transforms CLI applications from intimidating black boxes into guided, user-friendly experiences. It's the difference between asking users to read a manual and walking them through setup step by step." - Taylor Otwell, Creator of Laravel&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Laravel Prompts provides a beautiful, user-friendly interface for command-line applications with zero dependencies&lt;/li&gt;
&lt;li&gt;The package offers multiple input types including text, password, select, multiselect, confirm, search, and progress bars&lt;/li&gt;
&lt;li&gt;Laravel 12 includes Prompts natively, making CLI interactions more intuitive and visually appealing&lt;/li&gt;
&lt;li&gt;Prompts automatically handles validation, error messages, and keyboard navigation&lt;/li&gt;
&lt;li&gt;Perfect for creating installation wizards, configuration tools, and interactive artisan commands&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction to Laravel Prompts&lt;/li&gt;
&lt;li&gt;Understanding Laravel Prompts Components&lt;/li&gt;
&lt;li&gt;Statistics&lt;/li&gt;
&lt;li&gt;Available Prompt Types&lt;/li&gt;
&lt;li&gt;Practical Implementation: Database Seeder Generator&lt;/li&gt;
&lt;li&gt;AInteresting Facts&lt;/li&gt;
&lt;li&gt;Best Practices&lt;/li&gt;
&lt;li&gt;FAQ's&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Introduction to Laravel Prompts
&lt;/h2&gt;

&lt;p&gt;Laravel Prompts is a PHP package designed to add beautiful and user-friendly forms to command-line applications. Introduced in Laravel 10 and fully integrated into Laravel 12, it transforms the way developers build interactive CLI tools. The package eliminates the complexity of terminal interactions while maintaining a consistent, professional appearance across different operating systems.&lt;/p&gt;

&lt;p&gt;The beauty of Laravel Prompts lies in its simplicity. Developers no longer need to worry about cursor positioning, input validation styling, or cross-platform compatibility. Everything works seamlessly out of the box, allowing you to focus on building features rather than fighting with terminal quirks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Laravel Prompts Components
&lt;/h2&gt;

&lt;p&gt;Laravel Prompts consists of several core components that work together to create interactive experiences. At its foundation, the package uses a renderer that handles the visual presentation of prompts across different terminal emulators. The input handler manages keyboard events, supporting both arrow keys and vim-style navigation.&lt;/p&gt;

&lt;p&gt;The validation system integrates seamlessly with Laravel's existing validation rules. You can apply the same validation logic you use in web forms to your CLI prompts. Error messages appear inline, providing immediate feedback without disrupting the user's flow.&lt;br&gt;
Each prompt type is designed with specific use cases in mind. Text inputs handle single-line responses, select dropdowns present choices elegantly, and progress bars provide visual feedback during long-running operations.&lt;/p&gt;
&lt;h2&gt;
  
  
  Statistics
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Package Adoption and Performance Metrics: Laravel Prompts has been downloaded over 15 million times since its release (Source: &lt;a href="https://packagist.org/packages/laravel/prompts" rel="noopener noreferrer"&gt;Packagist.org&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;The package supports PHP 8.1+ and works across Windows, macOS, and Linux environments&lt;/li&gt;
&lt;li&gt;Laravel 12 includes Prompts as a first-party package, integrated directly into the framework&lt;/li&gt;
&lt;li&gt;Over 2,000+ GitHub stars on the official repository, demonstrating strong community adoption (Source: &lt;a href="https://github.com/laravel/prompts" rel="noopener noreferrer"&gt;GitHub Laravel Prompts&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;The package has zero runtime dependencies, keeping your application lightweight&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Available Prompt Types
&lt;/h2&gt;

&lt;p&gt;Laravel Prompts offers eight distinct prompt types, each optimized for specific interactions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Text Input&lt;/strong&gt; handles single-line text entry with placeholder support and real-time validation. Use it for names, URLs, or any short string input.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Textarea&lt;/strong&gt; provides multi-line input capabilities, perfect for descriptions or longer text content. Users can navigate with arrow keys and submit with Ctrl+D.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Password&lt;/strong&gt; masks input characters while typing, essential for sensitive information. The package ensures password fields never log or display their contents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Confirm&lt;/strong&gt; presents yes/no questions with keyboard shortcuts. Users can press Y/N or use arrow keys to select their choice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Select&lt;/strong&gt; creates dropdown menus for choosing from predefined options. It supports keyboard navigation and search functionality for longer lists.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multiselect&lt;/strong&gt; allows selecting multiple items from a list using the spacebar. Perfect for feature toggles or category selection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Search&lt;/strong&gt; combines text input with dynamic filtering, ideal for selecting from large datasets without overwhelming the user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Progress&lt;/strong&gt; Bars visualize long-running tasks, automatically updating as operations complete. They can display percentages, labels, and estimated time remaining.&lt;/p&gt;
&lt;h2&gt;
  
  
  Practical Implementation: Database Seeder Generator
&lt;/h2&gt;

&lt;p&gt;Let's build a real-world example: an interactive database seeder generator that helps developers quickly populate their applications with test data. This demonstrates how Laravel Prompts can transform a complex data generation process into a guided, intuitive experience.&lt;/p&gt;

&lt;p&gt;This wizard allows developers to select which models to seed, configure record counts, set up relationships, and save configurations as reusable presets-all through an elegant command-line interface.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before implementing this seeder generator, ensure you have:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Migrated all required database tables - Run php artisan migrate for your models (users, posts, comments, categories, etc.)&lt;/li&gt;
&lt;li&gt;Created models with proper relationships - Define HasMany, BelongsTo, and BelongsToMany relationships in your models&lt;/li&gt;
&lt;li&gt;Set up model factories - Create factories for each model using php artisan make:factory ModelNameFactory&lt;/li&gt;
&lt;li&gt;Defined fillable attributes - Ensure your models have the $fillable property set for mass assignment&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once your database structure, models, relationships, and factories are ready, create the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:command GenerateSeeder

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Complete Seeder Generator&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;
use function Laravel\Prompts\multiselect;
use function Laravel\Prompts\text;
use function Laravel\Prompts\select;
use function Laravel\Prompts\confirm;
use function Laravel\Prompts\info;
use function Laravel\Prompts\warning;
use function Laravel\Prompts\error;
use function Laravel\Prompts\table;
use function Laravel\Prompts\spin;

class GenerateSeeder extends Command
{
    protected $signature = 'seed:generate {--preset=}';
    protected $description = 'Interactive database seeder generator';

    private array $availableModels = [
        'User' =&amp;gt; \App\Models\User::class,
        'Post' =&amp;gt; \App\Models\Post::class,
        'Comment' =&amp;gt; \App\Models\Comment::class,
        'Category' =&amp;gt; \App\Models\Category::class,
        'Product' =&amp;gt; \App\Models\Product::class,
        'Order' =&amp;gt; \App\Models\Order::class,
        'Tag' =&amp;gt; \App\Models\Tag::class,
    ];

    private array $config = [];

    public function handle()
    {
        info('Interactive Database Seeder Generator');

        // Load preset if specified
        if ($this-&amp;gt;option('preset')) {
            if ($this-&amp;gt;loadPreset($this-&amp;gt;option('preset'))) {
                info("Loaded preset: {$this-&amp;gt;option('preset')}");
                $this-&amp;gt;showPresetSummary();

                if (confirm('Use this preset configuration?', default: true)) {
                    if ($this-&amp;gt;confirmExecution()) {
                        $this-&amp;gt;executeSeed();
                    }
                    return 0;
                }
            }
        }

        // Step 1: Model Selection
        $selectedModels = $this-&amp;gt;selectModels();

        if (empty($selectedModels)) {
            warning('No models selected. Exiting.');
            return 0;
        }

        // Step 2: Configure Counts
        $this-&amp;gt;configureCounts($selectedModels);

        // Step 3: Configure Relationships
        $this-&amp;gt;configureRelationships($selectedModels);

        // Step 4: Data Quality &amp;amp; Special Options
        $this-&amp;gt;configureOptions();

        // Step 5: Handle Existing Data
        $this-&amp;gt;handleExistingData();

        // Step 6: Show Summary
        $this-&amp;gt;showSummary();

        // Step 7: Confirm and Execute
        if ($this-&amp;gt;confirmExecution()) {
            $this-&amp;gt;executeSeed();
            $this-&amp;gt;offerToSave();
        } else {
            warning('Seeding cancelled.');
        }

        return 0;
    }

    private function selectModels(): array
    {
        $selectedKeys = multiselect(
            label: 'Which models do you want to seed?',
            options: $this-&amp;gt;availableModels,
            hint: 'Use space to select, enter to confirm'
        );

        // Convert keys to actual class paths
        $models = array_map(fn($key) =&amp;gt; $this-&amp;gt;availableModels[$key], $selectedKeys);

        // Check for relationship dependencies
        return $this-&amp;gt;checkDependencies($models);
    }

    private function checkDependencies(array $models): array
    {
        $dependencies = [
            'Comment' =&amp;gt; ['Post'],
            'Post' =&amp;gt; ['User'],
            'Order' =&amp;gt; ['User', 'Product'],
        ];

        foreach ($models as $model) {
            $modelName = class_basename($model);

            if (isset($dependencies[$modelName])) {
                foreach ($dependencies[$modelName] as $required) {
                    $requiredClass = $this-&amp;gt;availableModels[$required] ?? null;

                    if ($requiredClass &amp;amp;&amp;amp; !in_array($requiredClass, $models)) {
                        warning("{$modelName} requires {$required}.");

                        if (confirm("Would you like to auto-include {$required}?", default: true)) {
                            $models[] = $requiredClass;
                            info(" Added {$required} to seeding list.");
                        }
                    }
                }
            }
        }

        return array_unique($models);
    }

    private function configureCounts(array $models): void
    {
        info(' Configure Record Counts');

        foreach ($models as $model) {
            $modelName = class_basename($model);

            $count = text(
                label: "How many {$modelName} records?",
                default: $this-&amp;gt;getDefaultCount($modelName),
                required: true,
                validate: fn($value) =&amp;gt; is_numeric($value) &amp;amp;&amp;amp; $value &amp;gt; 0
                    ? null
                    : 'Please enter a valid number greater than 0',
                hint: $this-&amp;gt;getCountHint($modelName)
            );

            $this-&amp;gt;config['models'][$modelName] = [
                'class' =&amp;gt; $model,
                'count' =&amp;gt; (int)$count,
            ];
        }
    }

    private function configureRelationships(array $models): void
    {
        info('Configure Relationships');

        $modelNames = array_map(fn($m) =&amp;gt; class_basename($m), $models);

        if (in_array('Post', $modelNames) &amp;amp;&amp;amp; in_array('Category', $modelNames)) {
            $categoryAssignment = select(
                label: 'Assign Posts to Categories?',
                options: [
                    'multiple' =&amp;gt; 'Yes, assign each post to 1-3 categories (random)',
                    'single' =&amp;gt; 'Yes, assign each post to exactly 1 category',
                    'none' =&amp;gt; 'No, leave categories unassigned'
                ],
                default: 'multiple'
            );

            $this-&amp;gt;config['relationships']['post_category'] = $categoryAssignment;
        }

        if (in_array('Comment', $modelNames) &amp;amp;&amp;amp; in_array('User', $modelNames)) {
            $commentAuthors = select(
                label: 'Who should author comments?',
                options: [
                    'all' =&amp;gt; 'Any user (random)',
                    'subset' =&amp;gt; 'Only 30% of users are active commenters',
                    'post_author' =&amp;gt; 'Include self-comments from post authors'
                ],
                default: 'all'
            );

            $this-&amp;gt;config['relationships']['comment_user'] = $commentAuthors;
        }
    }

    private function configureOptions(): void
    {
        info('Additional Options');

        $realism = select(
            label: 'Data realism level',
            options: [
                'high' =&amp;gt; 'High (slower, more realistic data)',
                'medium' =&amp;gt; 'Medium (balanced)',
                'low' =&amp;gt; 'Low (fast, simple data)'
            ],
            default: 'medium',
            hint: 'Higher realism uses more varied faker data'
        );

        $this-&amp;gt;config['options']['realism'] = $realism;

        $specialCases = multiselect(
            label: 'Include special test cases?',
            options: [
                'admin' =&amp;gt; 'Create 1 admin user',
                'empty_users' =&amp;gt; 'Create 5 users with no posts',
                'featured' =&amp;gt; 'Create 3 featured posts',
                'suspended' =&amp;gt; 'Create 2 suspended users',
            ],
            hint: 'Optional - adds specific edge cases for testing'
        );

        $this-&amp;gt;config['options']['special_cases'] = $specialCases;

        if (isset($this-&amp;gt;config['models']['User'])) {
            info('User States Distribution');

            $activePercent = text(
                label: 'Percentage of active users',
                default: '80',
                validate: fn($v) =&amp;gt; is_numeric($v) &amp;amp;&amp;amp; $v &amp;gt;= 0 &amp;amp;&amp;amp; $v &amp;lt;= 100 
                    ? null 
                    : 'Enter 0-100'
            );

            $this-&amp;gt;config['options']['user_states'] = [
                'active' =&amp;gt; (int)$activePercent,
                'inactive' =&amp;gt; 100 - (int)$activePercent
            ];
        }
    }

    private function handleExistingData(): void
    {
        $hasData = false;

        foreach ($this-&amp;gt;config['models'] as $modelName =&amp;gt; $data) {
            $tableName = Str::snake(Str::plural($modelName));
            if (Schema::hasTable($tableName)) {
                if (DB::table($tableName)-&amp;gt;count() &amp;gt; 0) {
                    $hasData = true;
                    break;
                }
            }
        }

        if ($hasData) {
            warning('Database already contains data.');

            $action = select(
                label: 'What should we do?',
                options: [
                    'append' =&amp;gt; 'Add new records (append)',
                    'truncate' =&amp;gt; 'Truncate tables first (clean start)',
                    'skip' =&amp;gt; 'Cancel seeding'
                ],
                default: 'append'
            );

            $this-&amp;gt;config['options']['existing_data'] = $action;

            if ($action === 'skip') {
                warning('Seeding cancelled.');
                exit(0);
            }
        }
    }

    private function showSummary(): void
    {
        info('');
        info('═══════════════════════════════════════════════════');
        info('             Seeding Summary');
        info('═══════════════════════════════════════════════════');

        $tableData = [];
        $totalRecords = 0;

        foreach ($this-&amp;gt;config['models'] as $modelName =&amp;gt; $data) {
            $count = $data['count'];
            $totalRecords += $count;

            $tableData[] = [
                'Model' =&amp;gt; $modelName,
                'Records' =&amp;gt; number_format($count),
                'Table' =&amp;gt; Str::snake(Str::plural($modelName))
            ];
        }

        table(headers: ['Model', 'Records', 'Table'], rows: $tableData);

        info('');
        info("Total Records: " . number_format($totalRecords));
        info("Realism Level: " . ucfirst($this-&amp;gt;config['options']['realism'] ?? 'medium'));

        if (!empty($this-&amp;gt;config['options']['special_cases'])) {
            info("Special Cases: " . count($this-&amp;gt;config['options']['special_cases']) . " enabled");
        }

        $estimatedTime = max(1, (int)ceil($totalRecords / 100));
        info("Estimated Time: ~{$estimatedTime} seconds");

        info('═══════════════════════════════════════════════════');
        info('');
    }

    private function showPresetSummary(): void
    {
        info('');
        info('Preset Configuration:');

        if (isset($this-&amp;gt;config['models'])) {
            $tableData = [];
            foreach ($this-&amp;gt;config['models'] as $modelName =&amp;gt; $data) {
                $tableData[] = [
                    'Model' =&amp;gt; $modelName,
                    'Records' =&amp;gt; number_format($data['count'])
                ];
            }
            table(headers: ['Model', 'Records'], rows: $tableData);
        }
        info('');
    }

    private function confirmExecution(): bool
    {
        return confirm(
            label: 'Proceed with seeding?',
            default: true,
            yes: 'Yes, start seeding',
            no: 'Cancel'
        );
    }

    private function executeSeed(): void
    {
        info('Starting database seeding...');
        info('');

        if (($this-&amp;gt;config['options']['existing_data'] ?? '') === 'truncate') {
            spin(
                callback: function () {
                    foreach ($this-&amp;gt;config['models'] as $modelName =&amp;gt; $data) {
                        $tableName = Str::snake(Str::plural($modelName));
                        if (Schema::hasTable($tableName)) {
                            DB::table($tableName)-&amp;gt;truncate();
                        }
                    }
                },
                message: 'Truncating tables...'
            );
            info('Tables truncated');
        }

        foreach ($this-&amp;gt;config['models'] as $modelName =&amp;gt; $data) {
            $count = $data['count'];
            $class = $data['class'];

            if (!class_exists($class)) {
                warning("Model {$class} not found. Skipping.");
                continue;
            }

            $this-&amp;gt;seedModel($modelName, $class, $count);
        }

        info('');
        info('Database seeded successfully!');
        info('');
    }

    private function seedModel(string $modelName, string $class, int $count): void
    {
        $startTime = microtime(true);

        try {
            spin(
                callback: fn() =&amp;gt; $class::factory($count)-&amp;gt;create(),
                message: "Seeding {$modelName}..."
            );

            $duration = round(microtime(true) - $startTime, 2);
            info("Created {$count} {$modelName} records ({$duration}s)");

        } catch (\Exception $e) {
            error("Failed to seed {$modelName}: {$e-&amp;gt;getMessage()}");

            if (!confirm("Continue seeding other models?", default: true)) {
                throw $e;
            }
        }
    }

    private function offerToSave(): void
    {
        info('');

        if (confirm('Save this configuration as a preset?', default: false)) {
            $presetName = text(
                label: 'Preset name',
                placeholder: 'e.g., blog_testing, demo, performance',
                required: true,
                validate: fn($v) =&amp;gt; preg_match('/^[a-z0-9_]+$/', $v)
                    ? null
                    : 'Use lowercase letters, numbers, and underscores only'
            );

            $this-&amp;gt;savePreset($presetName);
            info("Configuration saved as preset: {$presetName}");
            info("Run again with: php artisan seed:generate --preset={$presetName}");
        }
    }

    private function savePreset(string $name): void
    {
        $presetsPath = storage_path('app/seeder-presets');
        if (!is_dir($presetsPath)) {
            mkdir($presetsPath, 0755, true);
        }
        file_put_contents(
            "{$presetsPath}/{$name}.json",
            json_encode($this-&amp;gt;config, JSON_PRETTY_PRINT)
        );
    }

    private function loadPreset(string $name): bool
    {
        $filePath = storage_path("app/seeder-presets/{$name}.json");
        if (!file_exists($filePath)) {
            return false;
        }
        $this-&amp;gt;config = json_decode(file_get_contents($filePath), true);
        return true;
    }

    private function getDefaultCount(string $modelName): string
    {
        return match($modelName) {
            'User' =&amp;gt; '50',
            'Post' =&amp;gt; '200',
            'Comment' =&amp;gt; '500',
            'Category' =&amp;gt; '10',
            'Product' =&amp;gt; '100',
            'Order' =&amp;gt; '300',
            'Tag' =&amp;gt; '20',
            default =&amp;gt; '50'
        };
    }

    private function getCountHint(string $modelName): string
    {
        return match($modelName) {
            'User' =&amp;gt; 'Recommended: 10-100 for testing',
            'Post' =&amp;gt; 'Recommended: 50-500 depending on use case',
            'Comment' =&amp;gt; 'Typically 2-5x the number of posts',
            'Category' =&amp;gt; 'Usually 5-20 categories',
            default =&amp;gt; 'Enter desired count'
        };
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;This wizard demonstrates several powerful features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Model selection with dependency checking - Automatically includes required models (e.g., Comments require Posts)&lt;/li&gt;
&lt;li&gt;Smart validation with inline error messages - Ensures valid numeric inputs and proper ranges&lt;/li&gt;
&lt;li&gt;Conditional prompts for relationships - Only asks relevant questions based on selected models&lt;/li&gt;
&lt;li&gt;Configuration preview with tables - Shows a clean summary before execution&lt;/li&gt;
&lt;li&gt;Preset system - Save configurations for reuse across different environments&lt;/li&gt;
&lt;li&gt;Progress feedback with spinners - Visual indication during long-running seed operations&lt;/li&gt;
&lt;li&gt;Error recovery - Gracefully handles failures and allows continuing with other models.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Usage Examples:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Interactive mode - walks through all options
php artisan seed:generate

# Quick start with preset
php artisan seed:generate --preset=blog_testing

# Common presets to create:
# - blog_testing: 50 users, 200 posts, 400 comments
# - demo: Beautiful data for client presentations
# - performance: 10,000+ records for load testing
# - minimal: Just enough data to start development
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach transforms database seeding from a manual, error-prone process into a guided experience that saves time and reduces mistakes. Developers can create consistent test environments across their team with saved presets, making onboarding and testing significantly easier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terminal Images For Reference:&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%2Fvzpjrlbakk5l11jqpeyk.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%2Fvzpjrlbakk5l11jqpeyk.png" alt=" " width="723" height="207"&gt;&lt;/a&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%2F0rmgcw22vo246okssms4.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%2F0rmgcw22vo246okssms4.png" alt=" " width="723" height="130"&gt;&lt;/a&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%2Fu9cwz82m65drbqw4my5q.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%2Fu9cwz82m65drbqw4my5q.png" alt=" " width="723" height="238"&gt;&lt;/a&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%2Fxzok5cznehpizacei8sx.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%2Fxzok5cznehpizacei8sx.png" alt=" " width="723" height="273"&gt;&lt;/a&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%2Fmpbl1fezbi5evt457aem.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%2Fmpbl1fezbi5evt457aem.png" alt=" " width="723" height="555"&gt;&lt;/a&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%2F28o0o8l1a5i5ecphl71a.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%2F28o0o8l1a5i5ecphl71a.png" alt=" " width="723" height="555"&gt;&lt;/a&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%2F6wbmjufbsqx23k3pfwrn.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%2F6wbmjufbsqx23k3pfwrn.png" alt=" " width="723" height="231"&gt;&lt;/a&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%2Fofjheb1mgakxxphd1ni3.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%2Fofjheb1mgakxxphd1ni3.png" alt=" " width="489" height="203"&gt;&lt;/a&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%2F8n3xdgq1oj2iqtsgf16z.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%2F8n3xdgq1oj2iqtsgf16z.png" alt=" " width="723" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Interesting Facts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Cross-Platform Compatibility Magic:&lt;/strong&gt; Laravel Prompts automatically detects the terminal environment and adjusts its rendering strategy. On Windows, it uses different control sequences than on Unix-based systems, ensuring consistent appearance everywhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zero Dependencies Philosophy:&lt;/strong&gt; Unlike most CLI packages that rely on external libraries, Laravel Prompts is entirely self-contained. This design decision keeps installations lightweight and reduces potential security vulnerabilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accessibility Features:&lt;/strong&gt; The package includes screen reader support and works with various terminal accessibility tools. Keyboard navigation follows standard conventions, making it intuitive for users familiar with terminal applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vim Keybinding Support:&lt;/strong&gt; Power users can navigate prompts using h, j, k, l keys in addition to arrow keys. This thoughtful addition shows Laravel's attention to developer experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fallback Mode:&lt;/strong&gt; When running in environments without TTY support (like CI/CD pipelines), Prompts automatically falls back to simple input/output, ensuring your commands work everywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;p&gt;Always provide clear, concise labels that explain what information you're requesting. Avoid technical jargon unless your audience expects it. Good labels reduce confusion and speed up the interaction process.&lt;/p&gt;

&lt;p&gt;Use validation early and provide helpful error messages. Instead of "Invalid input," tell users exactly what went wrong: "Port must be a number between 1 and 65535." This guidance prevents frustration and reduces support requests.&lt;/p&gt;

&lt;p&gt;Implement sensible defaults for every prompt when possible. Most users want the standard configuration, so let them press Enter to accept defaults. This respects their time while still allowing customization.&lt;/p&gt;

&lt;p&gt;Group related prompts together and use info/warning messages to provide context. Breaking complex configurations into logical sections makes the process feel manageable rather than overwhelming.&lt;br&gt;
Test your prompts in different terminal emulators. While Laravel Prompts handles most compatibility issues, verifying the experience across Windows Command Prompt, PowerShell, and various Unix shells ensures quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ's
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: Can I use Laravel Prompts outside of Laravel applications?&lt;/strong&gt; A: Yes! Laravel Prompts is framework-agnostic and works in any PHP project. Install it via Composer with composer require laravel/prompts and start using the functions immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: How do I handle prompts in automated testing?&lt;/strong&gt; A: Laravel Prompts includes testing helpers. Use the Prompt::fake() method in your tests to simulate user input without requiring actual terminal interaction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Do prompts work in Docker containers?&lt;/strong&gt; A: Yes, but ensure your container has TTY enabled. Use docker run -it or set tty: true in docker-compose.yml for interactive prompts to work properly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Can I customize the appearance of prompts?&lt;/strong&gt; A: While the default styling is consistent and professional, you can create custom prompt classes extending the base components if you need specific visual modifications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: What happens if a user cancels a prompt with Ctrl+C?&lt;/strong&gt; A: Laravel Prompts respects cancellation and throws a UserCancelledException. You can catch this exception to handle cleanup or display a cancellation message.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Are prompts compatible with Windows Command Prompt?&lt;/strong&gt; A: Absolutely. Laravel Prompts includes specific rendering logic for Windows environments, ensuring prompts look great in Command Prompt, PowerShell, and Windows Terminal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Can I use prompts for file selection?&lt;/strong&gt; A: While there's no built-in file browser prompt, you can combine search prompts with filesystem scanning to create effective file selection interfaces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: How do I add help text or hints to prompts?&lt;/strong&gt; A: Most prompt functions accept a hint parameter where you can provide additional context. This text appears below the prompt in a muted color.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The real power of Laravel Prompts isn't in replacing web forms-it's in making CLI tools accessible to developers who previously found terminal applications intimidating." - Freek Van der Herten, Laravel Developer&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Laravel Prompts represents a significant leap forward in command-line interface design. By providing beautiful, intuitive interactions with zero configuration, it removes the technical barriers that once made CLI development challenging. The package exemplifies Laravel's philosophy of developer happiness, extending it from web applications into the terminal.&lt;/p&gt;

&lt;p&gt;As Laravel 12 continues to evolve, Prompts will remain a cornerstone of CLI development within the ecosystem. Whether you're building installation wizards, deployment tools, or interactive maintenance commands, Laravel Prompts provides the foundation for creating terminal applications that users actually enjoy using.&lt;/p&gt;

&lt;p&gt;About the Author: &lt;em&gt;Vatsal is a web developer at &lt;a href="https://www.addwebsolution.com/our-capabilities/laravel-development-agency" rel="noopener noreferrer"&gt;AddWebSolution&lt;/a&gt;. Building web magic with Laravel, PHP, MySQL, Vue.js &amp;amp; more. Blending code, coffee, and creativity to bring ideas to life.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>laravelprompts</category>
      <category>php</category>
      <category>cli</category>
    </item>
    <item>
      <title>Laravel Testing Made Simple with Pest: Write Clean, Readable, and Fast Tests</title>
      <dc:creator>Vatsal Acharya</dc:creator>
      <pubDate>Fri, 21 Nov 2025 10:08:09 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/laravel-testing-made-simple-with-pest-write-clean-readable-and-fast-tests-2b44</link>
      <guid>https://dev.to/addwebsolutionpvtltd/laravel-testing-made-simple-with-pest-write-clean-readable-and-fast-tests-2b44</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;"Testing leads to failure, and failure leads to understanding."- Burt Rutan&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Testing is the backbone of reliable software, but let's be honest-traditional PHPUnit tests can feel verbose and intimidating. Enter Pest, a delightful PHP testing framework that brings simplicity, elegance, and speed to Laravel testing. If you've ever wished your tests could read like plain English while being powerful enough for complex scenarios, Pest is your answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Pest offers cleaner syntax than PHPUnit with a functional, expressive API that reads like natural language&lt;/li&gt;
&lt;li&gt;Seamless Laravel integration with built-in support for database testing, HTTP requests, and authentication&lt;/li&gt;
&lt;li&gt;Faster test execution through parallel testing and optimized architecture&lt;/li&gt;
&lt;li&gt;Expectation API makes assertions intuitive with chainable methods like expect($value)-&amp;gt;toBe(10)&lt;/li&gt;
&lt;li&gt;Higher-order testing reduces boilerplate code with reusable test patterns&lt;/li&gt;
&lt;li&gt;Plugin ecosystem extends functionality for coverage reports, watch mode, and more&lt;/li&gt;
&lt;li&gt;100% compatible with PHPUnit – migrate gradually or mix both frameworks in the same project&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;What is Pest and Why Use It?&lt;/li&gt;
&lt;li&gt;Getting Started with Pest in Laravel&lt;/li&gt;
&lt;li&gt;Writing Your First Pest Test&lt;/li&gt;
&lt;li&gt;The Expectation API: Readable Assertions&lt;/li&gt;
&lt;li&gt;Testing Laravel Features with Pest&lt;/li&gt;
&lt;li&gt;Advanced Pest Features&lt;/li&gt;
&lt;li&gt;Parallel Testing for Speed&lt;/li&gt;
&lt;li&gt;Migration from PHPUnit to Pest&lt;/li&gt;
&lt;li&gt;Stats &amp;amp; Practical Insights&lt;/li&gt;
&lt;li&gt;Interesting Facts&lt;/li&gt;
&lt;li&gt;FAQs&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What is Pest and Why Use It?
&lt;/h2&gt;

&lt;p&gt;Pest is a modern PHP testing framework built on top of PHPUnit, created by Nuno Maduro. It focuses on simplicity and developer experience while maintaining all the power of PHPUnit under the hood.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Choose Pest Over PHPUnit?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Traditional PHPUnit Test:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace Tests\Unit;

use PHPUnit\Framework\TestCase;

class MathTest extends TestCase
{
    public function test_addition_works_correctly()
    {
        $result = 2 + 2;
        $this-&amp;gt;assertEquals(4, $result);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Same Test in Pest:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

test('addition works correctly', function () {
    $result = 2 + 2;
    expect($result)-&amp;gt;toBe(4);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference is striking. Pest eliminates class boilerplate, uses natural language for test names, and provides an intuitive expectation API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started with Pest in Laravel
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;br&gt;
Install Pest via Composer in your Laravel project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require pestphp/pest --dev --with-all-dependencies
composer require pestphp/pest-plugin-laravel --dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Initialize Pest&lt;/strong&gt;&lt;br&gt;
Run the initialization command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan pest:install

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

&lt;/div&gt;



&lt;p&gt;This creates a Pest.php configuration file in your tests directory and sets up the necessary structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project Structure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After installation, your test structure looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tests/
├── Pest.php
├── Feature/
│   └── ExampleTest.php
└── Unit/
    └── ExampleTest.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Running Tests&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Execute your Pest tests with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan test
# or
./vendor/bin/pest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For specific tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./vendor/bin/pest --filter=user

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Writing Your First Pest Test
&lt;/h2&gt;

&lt;p&gt;Let's create a real-world example testing a user service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create the Test File&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan pest:test UserServiceTest --unit

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Write the Test&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

use App\Services\UserService;
use App\Models\User;

it('creates a user with valid data', function () {
    $service = new UserService();

    $userData = [
        'name' =&amp;gt; 'John Doe',
        'email' =&amp;gt; 'john@example.com',
        'password' =&amp;gt; 'password123'
    ];

    $user = $service-&amp;gt;create($userData);

    expect($user)-&amp;gt;toBeInstanceOf(User::class)
        -&amp;gt;and($user-&amp;gt;name)-&amp;gt;toBe('John Doe')
        -&amp;gt;and($user-&amp;gt;email)-&amp;gt;toBe('john@example.com');
});

it('throws exception for invalid email', function () {
    $service = new UserService();

    $userData = [
        'name' =&amp;gt; 'John Doe',
        'email' =&amp;gt; 'invalid-email',
        'password' =&amp;gt; 'password123'
    ];

    $service-&amp;gt;create($userData);
})-&amp;gt;throws(ValidationException::class);

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;"Programs must be written for people to read, and only incidentally for machines to execute."- Harold Abelson&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Expectation API: Readable Assertions
&lt;/h2&gt;

&lt;p&gt;Pest's expectation API is one of its killer features. Instead of cryptic assertion methods, you get chainable, readable expectations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common Expectations&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Value comparisons
expect($value)-&amp;gt;toBe(10);
expect($value)-&amp;gt;toEqual($expected);
expect($value)-&amp;gt;toBeGreaterThan(5);
expect($value)-&amp;gt;toBeLessThan(100);

// Type checking
expect($user)-&amp;gt;toBeInstanceOf(User::class);
expect($value)-&amp;gt;toBeString();
expect($value)-&amp;gt;toBeInt();
expect($value)-&amp;gt;toBeBool();
expect($value)-&amp;gt;toBeArray();

// Null checks
expect($value)-&amp;gt;toBeNull();
expect($value)-&amp;gt;not-&amp;gt;toBeNull();

// Boolean checks
expect($value)-&amp;gt;toBeTrue();
expect($value)-&amp;gt;toBeFalse();
expect($condition)-&amp;gt;toBeTruthy();

// Array expectations
expect($array)-&amp;gt;toHaveCount(3);
expect($array)-&amp;gt;toContain('apple');
expect($array)-&amp;gt;toHaveKey('name');

// String expectations
expect($string)-&amp;gt;toStartWith('Hello');
expect($string)-&amp;gt;toEndWith('world');
expect($string)-&amp;gt;toContain('Laravel');
expect($email)-&amp;gt;toMatch('/^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/');

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Chaining Expectations&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expect($user)
    -&amp;gt;toBeInstanceOf(User::class)
    -&amp;gt;and($user-&amp;gt;email)-&amp;gt;toBeString()
    -&amp;gt;and($user-&amp;gt;isActive())-&amp;gt;toBeTrue()
    -&amp;gt;and($user-&amp;gt;roles)-&amp;gt;toHaveCount(2);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing Laravel Features with Pest
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Database Testing&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

it('stores user in database', function () {
    $user = User::factory()-&amp;gt;create([
        'name' =&amp;gt; 'Jane Doe'
    ]);

    expect($user-&amp;gt;exists)-&amp;gt;toBeTrue();

    $this-&amp;gt;assertDatabaseHas('users', [
        'name' =&amp;gt; 'Jane Doe'
    ]);
});

it('deletes user from database', function () {
    $user = User::factory()-&amp;gt;create();
    $userId = $user-&amp;gt;id;

    $user-&amp;gt;delete();

    $this-&amp;gt;assertDatabaseMissing('users', [
        'id' =&amp;gt; $userId
    ]);
});

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;HTTP Testing&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;it('returns successful login response', function () {
    $user = User::factory()-&amp;gt;create([
        'password' =&amp;gt; bcrypt('password')
    ]);

    $response = $this-&amp;gt;postJson('/api/login', [
        'email' =&amp;gt; $user-&amp;gt;email,
        'password' =&amp;gt; 'password'
    ]);

    $response-&amp;gt;assertOk()
        -&amp;gt;assertJsonStructure([
            'token',
            'user' =&amp;gt; ['id', 'name', 'email']
        ]);
});

it('validates registration input', function () {
    $response = $this-&amp;gt;postJson('/api/register', [
        'name' =&amp;gt; '',
        'email' =&amp;gt; 'invalid-email'
    ]);

    $response-&amp;gt;assertStatus(422)
        -&amp;gt;assertJsonValidationErrors(['name', 'email']);
});

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Authentication Testing&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use App\Models\User;

it('requires authentication for dashboard', function () {
    $response = $this-&amp;gt;get('/dashboard');

    $response-&amp;gt;assertRedirect('/login');
});

it('allows authenticated users to view dashboard', function () {
    $user = User::factory()-&amp;gt;create();

    $response = $this-&amp;gt;actingAs($user)-&amp;gt;get('/dashboard');

    $response-&amp;gt;assertOk()
        -&amp;gt;assertSee('Welcome, ' . $user-&amp;gt;name);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Testing Jobs and Events&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use App\Jobs\SendWelcomeEmail;
use App\Events\UserRegistered;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Facades\Event;

it('dispatches welcome email job', function () {
    Queue::fake();

    $user = User::factory()-&amp;gt;create();

    SendWelcomeEmail::dispatch($user);

    Queue::assertPushed(SendWelcomeEmail::class, function ($job) use ($user) {
        return $job-&amp;gt;user-&amp;gt;id === $user-&amp;gt;id;
    });
});

it('fires user registered event', function () {
    Event::fake();

    $user = User::factory()-&amp;gt;create();

    Event::assertDispatched(UserRegistered::class, function ($event) use ($user) {
        return $event-&amp;gt;user-&amp;gt;id === $user-&amp;gt;id;
    });
});

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Advanced Pest Features
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Higher-Order Tests&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Reduce duplication with higher-order test methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;it('has correct user properties')
    -&amp;gt;expect(fn() =&amp;gt; User::factory()-&amp;gt;create())
    -&amp;gt;toBeInstanceOf(User::class)
    -&amp;gt;toHaveProperty('email')
    -&amp;gt;toHaveProperty('name');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Custom Expectations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create reusable custom expectations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tests/Pest.php
expect()-&amp;gt;extend('toBeValidEmail', function () {
    return $this-&amp;gt;toMatch('/^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/');
});

// In your test
expect('user@example.com')-&amp;gt;toBeValidEmail();

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Datasets&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Test multiple scenarios with datasets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;it('validates email formats', function ($email, $isValid) {
    $validator = Validator::make(
        ['email' =&amp;gt; $email],
        ['email' =&amp;gt; 'email']
    );

    expect($validator-&amp;gt;passes())-&amp;gt;toBe($isValid);
})-&amp;gt;with([
    ['valid@example.com', true],
    ['invalid-email', false],
    ['user@domain', false],
    ['user@domain.com', true],
]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Shared Setup with beforeEach&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;beforeEach(function () {
    $this-&amp;gt;user = User::factory()-&amp;gt;create();
    $this-&amp;gt;actingAs($this-&amp;gt;user);
});

it('allows user to update profile', function () {
    $response = $this-&amp;gt;patch('/profile', [
        'name' =&amp;gt; 'Updated Name'
    ]);

    $response-&amp;gt;assertOk();
    expect($this-&amp;gt;user-&amp;gt;fresh()-&amp;gt;name)-&amp;gt;toBe('Updated Name');
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Test Filtering with Groups&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;it('processes payment', function () {
    // test code
})-&amp;gt;group('payments', 'integration');

// Run only payment tests
// ./vendor/bin/pest --group=payments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Skip and Todo&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;it('handles complex scenario')-&amp;gt;skip('Not implemented yet');

it('tests new feature')-&amp;gt;todo();

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Parallel Testing for Speed
&lt;/h2&gt;

&lt;p&gt;Pest supports parallel test execution for dramatic speed improvements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enable Parallel Testing&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./vendor/bin/pest --parallel

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Configure in Pest.php&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tests/Pest.php
uses(TestCase::class)-&amp;gt;in('Feature', 'Unit');

// Enable parallel execution
pest()-&amp;gt;parallel();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Performance Comparison&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Sequential
./vendor/bin/pest
# Time: 45.32 seconds

# Parallel
./vendor/bin/pest --parallel
# Time: 12.18 seconds (73% faster)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Migration from PHPUnit to Pest
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Gradual Migration Strategy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You don't need to migrate everything at once. Pest and PHPUnit coexist perfectly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install Pest alongside existing PHPUnit tests&lt;/li&gt;
&lt;li&gt;Write new tests in Pest while keeping old ones&lt;/li&gt;
&lt;li&gt;Migrate selectively when refactoring existing features&lt;/li&gt;
&lt;li&gt;Run both with php artisan test&lt;/li&gt;
&lt;li&gt;Conversion Example&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Before (PHPUnit):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace Tests\Unit;

use PHPUnit\Framework\TestCase;
use App\Services\Calculator;

class CalculatorTest extends TestCase
{
    private Calculator $calculator;

    protected function setUp(): void
    {
        parent::setUp();
        $this-&amp;gt;calculator = new Calculator();
    }

    public function test_it_adds_numbers()
    {
        $result = $this-&amp;gt;calculator-&amp;gt;add(2, 3);
        $this-&amp;gt;assertEquals(5, $result);
    }

    public function test_it_throws_exception_for_division_by_zero()
    {
        $this-&amp;gt;expectException(\DivisionByZeroError::class);
        $this-&amp;gt;calculator-&amp;gt;divide(10, 0);
    }
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After (Pest):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

use App\Services\Calculator;

beforeEach(function () {
    $this-&amp;gt;calculator = new Calculator();
});

it('adds numbers', function () {
    $result = $this-&amp;gt;calculator-&amp;gt;add(2, 3);
    expect($result)-&amp;gt;toBe(5);
});

it('throws exception for division by zero', function () {
    $this-&amp;gt;calculator-&amp;gt;divide(10, 0);
})-&amp;gt;throws(DivisionByZeroError::class);

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Stats &amp;amp; Practical Insights
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Performance Metrics&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code reduction: Pest tests average 30-40% fewer lines than equivalent PHPUnit tests&lt;/li&gt;
&lt;li&gt;Parallel execution: Can reduce test suite time by 60-80% on multi-core systems&lt;/li&gt;
&lt;li&gt;Adoption rate: Over 50,000+ projects on GitHub use Pest (as of 2024)&lt;/li&gt;
&lt;li&gt;Laravel community: Pest is the recommended testing framework by many Laravel developers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real-World Use Cases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;E-commerce Platform Testing&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Product inventory management
it('decrements stock after purchase', function () {
    $product = Product::factory()-&amp;gt;create(['stock' =&amp;gt; 10]);

    $order = Order::create([
        'product_id' =&amp;gt; $product-&amp;gt;id,
        'quantity' =&amp;gt; 3
    ]);

    expect($product-&amp;gt;fresh()-&amp;gt;stock)-&amp;gt;toBe(7);
});

// Discount calculation
it('applies percentage discount correctly', function () {
    $cart = new ShoppingCart();
    $cart-&amp;gt;addItem(100);
    $cart-&amp;gt;applyDiscount(20); // 20%

    expect($cart-&amp;gt;getTotal())-&amp;gt;toBe(80.0);
});

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;API Rate Limiting&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;it('blocks requests after rate limit', function () {
    $user = User::factory()-&amp;gt;create();

    // Make 60 requests (assuming limit is 60/minute)
    for ($i = 0; $i &amp;lt; 60; $i++) {
        $this-&amp;gt;actingAs($user)-&amp;gt;get('/api/endpoint');
    }

    $response = $this-&amp;gt;actingAs($user)-&amp;gt;get('/api/endpoint');

    $response-&amp;gt;assertStatus(429); // Too Many Requests
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Email Notification Testing&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Illuminate\Support\Facades\Mail;
use App\Mail\OrderConfirmation;

it('sends order confirmation email', function () {
    Mail::fake();

    $order = Order::factory()-&amp;gt;create();

    $order-&amp;gt;sendConfirmation();

    Mail::assertSent(OrderConfirmation::class, function ($mail) use ($order) {
        return $mail-&amp;gt;order-&amp;gt;id === $order-&amp;gt;id;
    });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Interesting Facts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Creator: Pest was created by Nuno Maduro, a Laravel core team member and creator of Laravel Zero&lt;/li&gt;
&lt;li&gt;Philosophy: Inspired by Jest (JavaScript) with a focus on simplicity and developer happiness&lt;/li&gt;
&lt;li&gt;Compatibility: 100% compatible with PHPUnit - uses PHPUnit internally&lt;/li&gt;
&lt;li&gt;Plugins: Over 20 official and community plugins available for extended functionality&lt;/li&gt;
&lt;li&gt;Zero Configuration: Works out-of-the-box with sensible defaults&lt;/li&gt;
&lt;li&gt;Type Coverage: Pest 3.x includes built-in type coverage analysis to ensure your tests use proper types&lt;/li&gt;
&lt;li&gt;Architecture Testing: Pest includes Arch testing to enforce architectural rules (e.g., "controllers should not access models directly")&lt;/li&gt;
&lt;li&gt;Community Growth: Pest has grown to over 9,000 GitHub stars since its launch in 2020&lt;/li&gt;
&lt;li&gt;Laravel Integration: Officially recognized and recommended by Laravel documentation&lt;/li&gt;
&lt;li&gt;Watch Mode: Pest can automatically rerun tests when files change with --watch flag&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;"Quality is not an act, it is a habit."- Aristotle&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  FAQs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Is Pest faster than PHPUnit?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, Pest is generally faster, especially with parallel testing enabled. The framework is optimized for performance, and parallel execution can reduce test suite time by 60-80%. The functional syntax also reduces overhead from class instantiation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Can I use Pest and PHPUnit together in the same project?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Absolutely! Pest is built on top of PHPUnit, so they coexist perfectly. You can have some tests in PHPUnit and others in Pest. Both will run when you execute php artisan test. This makes migration easy and gradual.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Does Pest support code coverage reports?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. Run Pest with the coverage flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./vendor/bin/pest --coverage

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

&lt;/div&gt;



&lt;p&gt;For detailed HTML reports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./vendor/bin/pest --coverage --coverage-html=coverage-report

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. How do I debug failing Pest tests?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use the same debugging techniques as PHPUnit:&lt;br&gt;
Add dd() or dump() in your test&lt;br&gt;
Use --filter to run specific tests: ./vendor/bin/pest --filter=user&lt;br&gt;
Use --bail to stop on first failure: ./vendor/bin/pest --bail&lt;br&gt;
Enable verbose mode: ./vendor/bin/pest -v&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Can I use Pest for non-Laravel PHP projects?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes! While Pest has excellent Laravel integration, it works with any PHP project. Just install the base Pest package without the Laravel plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require pestphp/pest --dev

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. What's the difference between test() and it()?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They're functionally identical - just syntactic sugar for readability:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test('user can login', function () { ... });
it('allows user to login', function () { ... });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Choose whichever reads better for your test description.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. How do I test private or protected methods with Pest?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Generally, you shouldn't test private methods directly - test public behavior instead. If absolutely necessary, use reflection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$reflection = new ReflectionClass($object);
$method = $reflection-&amp;gt;getMethod('privateMethod');
$method-&amp;gt;setAccessible(true);
$result = $method-&amp;gt;invoke($object);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;8. Does Pest support snapshot testing?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, with the pestphp/pest-plugin-snapshots plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require pestphp/pest-plugin-snapshots --dev

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

&lt;/div&gt;



&lt;p&gt;Then use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expect($data)-&amp;gt;toMatchSnapshot();

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;9. How do I run only unit tests or feature tests?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use directory filtering:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./vendor/bin/pest tests/Unit

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./vendor/bin/pest tests/Feature

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;10. Can Pest run tests in random order?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, use the --order-random flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./vendor/bin/pest --order-random

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

&lt;/div&gt;



&lt;p&gt;This helps identify tests with hidden dependencies on execution order.&lt;/p&gt;

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

&lt;p&gt;Pest transforms Laravel testing from a chore into a delightful experience. Its clean, expressive syntax reduces boilerplate while maintaining all the power of PHPUnit underneath. Whether you're testing APIs, database interactions, or complex business logic, Pest makes your tests more readable, maintainable, and faster to execute.&lt;/p&gt;

&lt;p&gt;About the Author: &lt;em&gt;Vatsal is a web developer at &lt;a href="https://www.addwebsolution.com/our-capabilities/laravel-development-agency" rel="noopener noreferrer"&gt;AddWebSolution&lt;/a&gt;. Building web magic with Laravel, PHP, MySQL, Vue.js &amp;amp; more. Blending code, coffee, and creativity to bring ideas to life.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>pestphp</category>
      <category>softwaretesting</category>
      <category>cleancoding</category>
    </item>
    <item>
      <title>MySQL Transactions &amp; Data Integrity in Laravel</title>
      <dc:creator>Vatsal Acharya</dc:creator>
      <pubDate>Tue, 04 Nov 2025 08:34:43 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/mysql-transactions-data-integrity-in-laravel-2g65</link>
      <guid>https://dev.to/addwebsolutionpvtltd/mysql-transactions-data-integrity-in-laravel-2g65</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;“Without Data, you’re just another person with an opinion.” - W. Edwards Deming&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use DB::transaction() (closure) for most cases - it auto-commits or rolls back on exception.&lt;/li&gt;
&lt;li&gt;Laravel emulates nested transactions with savepoints when the DB supports them (e.g., MySQL/InnoDB). Keep nesting shallow - savepoints add complexity.&lt;/li&gt;
&lt;li&gt;For concurrency control use pessimistic locks (lockForUpdate() / sharedLock()) or implement optimistic locking (version column + conditional update) depending on contention patterns.&lt;/li&gt;
&lt;li&gt;DB::transaction(..., $attempts) will retry the closure when a database deadlock occurs; it does not retry on arbitrary exceptions - plan accordingly.&lt;/li&gt;
&lt;li&gt;Avoid DDL/implicit-commit statements inside transactions and avoid external network I/O inside transactions (or dispatch those jobs -&amp;gt;afterCommit()).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Why transactions &amp;amp; ACID matter&lt;/li&gt;
&lt;li&gt;MySQL (InnoDB) specifics you must know&lt;/li&gt;
&lt;li&gt;Laravel 12 transaction API (quick reference + examples)&lt;/li&gt;
&lt;li&gt;Nested transactions &amp;amp; savepoints (how Laravel handles them)&lt;/li&gt;
&lt;li&gt;Locks: pessimistic (lockForUpdate / sharedLock) vs optimistic (versioning)&lt;/li&gt;
&lt;li&gt;Deadlocks, retries, and how to handle them safely&lt;/li&gt;
&lt;li&gt;Common pitfalls (DDL, implicit commits, jobs &amp;amp; events) + how to avoid them&lt;/li&gt;
&lt;li&gt;Testing transactions&lt;/li&gt;
&lt;li&gt;Advanced patterns (distributed transactions, sagas)&lt;/li&gt;
&lt;li&gt;Practical examples&lt;/li&gt;
&lt;li&gt;Stats&lt;/li&gt;
&lt;li&gt;Interesting Facts&lt;/li&gt;
&lt;li&gt;FAQs&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1 - Why transactions &amp;amp; ACID matter
&lt;/h2&gt;

&lt;p&gt;Transactions give you atomicity (all-or-nothing), consistency (DB constraints upheld), isolation (concurrent work doesn’t clobber you) and durability (committed changes survive). For business-critical flows - payments, inventory decrement, multi-table writes - wrap related DB actions in transactions to avoid partial state.&lt;/p&gt;

&lt;h2&gt;
  
  
  2 - MySQL (InnoDB) specifics you must know
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use InnoDB for transactions, row-level locking, and foreign keys. Many features (transactional semantics, FK checks) depend on it.&lt;/li&gt;
&lt;li&gt;Isolation level influences visibility and anomalies (dirty/read/write skew). MySQL default is REPEATABLE READ (but you can change per-session or server). Test your workload under the isolation level you use.&lt;/li&gt;
&lt;li&gt;Savepoints are supported by InnoDB and allow emulated nested transactions. DDL will often cause implicit commits - don’t run CREATE TABLE / ALTER TABLE inside a transaction you expect to keep open.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3 - Laravel 12 transaction API (reference + examples)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Auto-managed closure (the usual)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Illuminate\Support\Facades\DB;

DB::transaction(function () {
    // Eloquent or Query Builder operations here
    $user = User::create([...]);
    $order = Order::create(['user_id' =&amp;gt; $user-&amp;gt;id, 'total' =&amp;gt; 100]);
    $order-&amp;gt;items()-&amp;gt;createMany($items);
});
// on exception -&amp;gt; rollback; on success -&amp;gt; commit

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Laravel docs: DB::transaction() auto-commits or auto-rolls back and can accept a second param for deadlock retry attempts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Manual begin/commit/rollback&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB::beginTransaction();

try {
    // multiple operations spanning functions/classes
    $invoice = Invoice::create([...]);
    // maybe call services that modify DB
    DB::commit();
} catch (\Throwable $e) {
    DB::rollBack();
    throw $e; // rethrow or handle
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Retry on deadlock&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB::transaction(function () {
    // high-contention updates
}, 5); // try up to 5 times if a deadlock occurs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4 - Nested transactions &amp;amp; savepoints
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MySQL doesn’t support true nested transactions&lt;/strong&gt;, but InnoDB supports SAVEPOINT. Laravel counts transaction nesting levels and uses savepoints under the hood where supported. That means you can call DB::beginTransaction() multiple times in the call stack - Laravel will create savepoints rather than starting separate DB transactions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gotchas:&lt;/strong&gt; savepoints increase complexity; behavior around RELEASE SAVEPOINT or committing a nested level has been the subject of issues in the past - be careful and test. Avoid deep nesting; prefer letting a single outer transaction orchestrate the unit of work.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB::beginTransaction();             // outer
try {
    // do something
    DB::beginTransaction();         // inner -&amp;gt; creates SAVEPOINT
    try {
        // do something that may fail
        DB::commit();               // releases savepoint (emulated)
    } catch (\Throwable $innerEx) {
        DB::rollBack();             // rollback to savepoint
    }
    DB::commit();                   // commit outer
} catch (\Throwable $e) {
    DB::rollBack();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5 - Locks: pessimistic vs optimistic
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pessimistic locking (when you must block others)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Laravel provides lockForUpdate() and sharedLock() on query builder / Eloquent -&lt;br&gt;
these map to SELECT ... FOR UPDATE and shared locks. Wrap them in a transaction &lt;br&gt;
for correctness. Use for critical updates (balances, inventory).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example - safe money transfer&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB::transaction(function () use ($fromId, $toId, $amount) {
    $from = DB::table('accounts')-&amp;gt;where('id', $fromId)-&amp;gt;lockForUpdate()-&amp;gt;first();
    $to   = DB::table('accounts')-&amp;gt;where('id', $toId)-&amp;gt;lockForUpdate()-&amp;gt;first();

    if ($from-&amp;gt;balance &amp;lt; $amount) {
        throw new \RuntimeException('Insufficient funds');
    }

    DB::table('accounts')-&amp;gt;where('id', $fromId)-&amp;gt;decrement('balance', $amount);
    DB::table('accounts')-&amp;gt;where('id', $toId)-&amp;gt;increment('balance', $amount);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Optimistic locking (low-contention, high throughput)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Laravel doesn't provide built-in optimistic locking. Implement it with a version (or use&lt;br&gt;
updated_at ) column and perform a conditional update (WHERE id = ? AND version =&lt;br&gt;
 ?) and check affected rows. If 0 rows updated → conflict→ retry/respond.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Optimistic example&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// migration: $table-&amp;gt;unsignedInteger('version')-&amp;gt;default(0);

$updated = DB::table('tickets')
    -&amp;gt;where('id', $id)
    -&amp;gt;where('version', $clientVersion)
    -&amp;gt;update([
        'status' =&amp;gt; 'sold',
        'version' =&amp;gt; $clientVersion + 1,
    ]);

if (! $updated) {
    // conflict — return 409, or retry read-&amp;gt;apply pattern
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optimistic locking is efficient when collisions are rare. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“You can have all of the fancy tools, but if your data quality is not good, you’re&lt;br&gt;
nowhere.” - Veda Bawo&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  6 - Deadlocks, retries, and safe side-effects
&lt;/h2&gt;

&lt;p&gt;Deadlocks can happen in high-concurrency workloads (two transactions lock rows in opposite order). Use DB::transaction(..., $attempts) to let Laravel retry on deadlocks. But only deadlocks are automatically retried; arbitrary exceptions are not. Also be careful with side effects inside the closure (external HTTP calls, emails) because retries re-run the closure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Safe pattern&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep transactions small and DB-only (no external HTTP).&lt;/li&gt;
&lt;li&gt;If you need to call external systems, commit first or dispatch jobs        &amp;gt;afterCommit() (see section below).&lt;/li&gt;
&lt;li&gt;If you must retry, log each attempt and use exponential backoff on retries outside DB closure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7 - Common pitfalls &amp;amp; how to avoid them
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1) DDL / implicit commits&lt;/strong&gt;&lt;br&gt;
Running DDL (e.g., CREATE TABLE, some ALTER TABLE) inside a transaction can trigger an implicit commit in MySQL - your transaction semantics break. Don’t perform schema changes inside app transactions. Laravel docs warn about this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2) External I/O inside transactions&lt;/strong&gt;&lt;br&gt;
Avoid external network calls (HTTP, SMTP) inside transactions - failures or retries are complex. If you must dispatch jobs or send mails after commit, use -&amp;gt;afterCommit():&lt;br&gt;
ProcessOrderJob::dispatch($order)-&amp;gt;afterCommit();&lt;br&gt;
This ensures the job is queued only after the DB transaction commits. (Also configurable via after_commit queue option.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3) Events dispatched inside transactions&lt;/strong&gt;&lt;br&gt;
Recent Laravel versions added improved behavior so events can be aware of transactions; still, be careful with queued listeners - use afterCommit or dispatch from an event listener that's transactional-aware.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4) Cross-connection atomicity&lt;/strong&gt;&lt;br&gt;
Laravel transactions are per database connection. If your use-case requires atomicity across multiple database servers, you’ll need a distributed transaction coordinator (2PC/XA) or a different architecture (saga patterns). In practice: avoid multi-DB atomic transactions unless you really need them.&lt;/p&gt;
&lt;h2&gt;
  
  
  8 -Testing transactions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use Laravel’s testing tools (RefreshDatabase, DatabaseTransactions trait when appropriate) for reproducible tests. Tests often wrap a test in a transaction and roll it back so DB state is clean. See Laravel database testing docs.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;“Data is a living thing. It must be nurtured and protected.” - Thomas Redman&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  9 - Advanced: distributed transactions &amp;amp; sagas
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Two-phase commit (XA/2PC) exists but is complex and painful (coordinator, locking, failure modes). Most modern apps prefer compensating transactions / saga patterns for multi-service workflows. If you absolutely need multi-DB atomicity, research XA or a distributed transaction manager - but prefer architecture that avoids cross-DB transactions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  10 - Practical examples
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A. Create order + decrement stock&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB::transaction(function () use ($userData, $cartItems) {
    $user = User::create($userData);
    $order = Order::create(['user_id' =&amp;gt; $user-&amp;gt;id, 'total' =&amp;gt; array_sum(array_column($cartItems, 'price'))]);

    foreach ($cartItems as $item) {
        // lock product row and update stock safely
        $product = Product::where('id', $item['product_id'])-&amp;gt;lockForUpdate()-&amp;gt;first();

        if ($product-&amp;gt;stock &amp;lt; $item['qty']) {
            throw new \RuntimeException("Out of stock for product {$product-&amp;gt;id}");
        }

        $product-&amp;gt;decrement('stock', $item['qty']);
        $order-&amp;gt;items()-&amp;gt;create([
            'product_id' =&amp;gt; $product-&amp;gt;id,
            'price' =&amp;gt; $item['price'],
            'qty' =&amp;gt; $item['qty'],
        ]);
    }

    // dispatch email after commit to avoid race conditions
    SendOrderConfirmation::dispatch($order)-&amp;gt;afterCommit();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;B. Optimistic update with retry&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function updateNameOptimistic(int $id, string $newName, int $currentVersion) {
    $affected = DB::table('profiles')
        -&amp;gt;where('id', $id)
        -&amp;gt;where('version', $currentVersion)
        -&amp;gt;update([
            'name' =&amp;gt; $newName,
            'version' =&amp;gt; $currentVersion + 1,
            'updated_at' =&amp;gt; now(),
        ]);

    if (! $affected) {
        // conflict detected
        throw new \RuntimeException('Conflict: profile updated by another request. Try again.');
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;C. Manual savepoint example (nested transaction emulation)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB::beginTransaction(); // start outer
try {
    // work A

    DB::beginTransaction(); // creates savepoint
    try {
        // work B that may fail
        DB::commit(); // releases inner savepoint
    } catch (\Throwable $e) {
        DB::rollBack(); // rollback to savepoint (undo B only)
        // handle or rethrow
    }

    // continue work A
    DB::commit();
} catch (\Throwable $e) {
    DB::rollBack();
    throw $e;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  11 - Stats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Default MySQL (InnoDB) isolation level: REPEATABLE READ. &lt;a href="https://dev.mysql.com/doc/refman/8.4/en/innodb-transaction-isolation-levels.html" rel="noopener noreferrer"&gt;https://dev.mysql.com/doc/refman/8.4/en/innodb-transaction-isolation-levels.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;DB::transaction($closure, 5) - the second parameter tells Laravel how many times to retry on deadlock (example 5). &lt;a href="https://laravel.com/docs/12.x/database" rel="noopener noreferrer"&gt;https://laravel.com/docs/12.x/database&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  12 - Interesting facts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Savepoints let you “roll back partially” within the same transaction, but you can’t magically remove a set of changes in the middle without undoing everything above it (savepoints act like a stack).&lt;a href="https://dev.mysql.com/doc/refman/9.0/en/savepoint.html" rel="noopener noreferrer"&gt;https://dev.mysql.com/doc/refman/9.0/en/savepoint.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Some SQL statements (DDL) trigger an implicit commit in MySQL - executing them inside an open transaction will commit the whole transaction behind Laravel’s back. Laravel warns about this.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  13 - FAQs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q - Will DB::transaction() retry my closure on any exception?&lt;/strong&gt;&lt;br&gt;
A - No. The optional second parameter sets how many times to retry for deadlocks.Other exceptions will not trigger automatic retry. Plan side effects with that in mind.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q - Can I dispatch a queued job from inside a transaction?&lt;/strong&gt;&lt;br&gt;
A - Yes - but prefer -&amp;gt;afterCommit() to ensure jobs are queued only after the transaction successfully commits. Otherwise the job might run before DB changes are durable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q - Are nested transactions safe?&lt;/strong&gt;&lt;br&gt;
A - Laravel emulates nested transactions using savepoints when supported; it works but adds complexity - avoid deep nesting and test savepoint behavior on&lt;br&gt;
your MySQL version.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q - Do schema changes rollback if my transaction fails?&lt;/strong&gt;&lt;br&gt;
A - No. DDL often causes implicit commits - don’t rely on rolling back schema changes. Use migrations instead of runtime DDL.&lt;/p&gt;

&lt;h2&gt;
  
  
  14 - Conclusion
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Keep the transaction small and DB-only (no HTTP/mail during the transaction). Use afterCommit() for jobs.&lt;/li&gt;
&lt;li&gt;Use lockForUpdate() where you need exclusive access, or optimistic locking when collisions are rare.&lt;/li&gt;
&lt;li&gt;Add deadlock retry logic: DB::transaction($closure, $attempts) and add logging/backoff.&lt;/li&gt;
&lt;li&gt;Avoid DDL/statements that trigger implicit commit inside transactions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;About the Author: Vatsal is a web developer at &lt;a href="https://www.addwebsolution.com/" rel="noopener noreferrer"&gt;AddWebSolution&lt;/a&gt;. Building web magic with Laravel, PHP, MySQL, Vue.js &amp;amp; more. Blending code, coffee, and creativity to bring ideas to life.&lt;/p&gt;

</description>
      <category>laravel12</category>
      <category>mysqltransactions</category>
      <category>dataintegrity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Getting Started with Laravel API Resources for Clean JSON Responses In Laravel</title>
      <dc:creator>Vatsal Acharya</dc:creator>
      <pubDate>Wed, 30 Jul 2025 11:44:44 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/getting-started-with-laravel-api-resources-for-clean-json-responses-in-laravel-525m</link>
      <guid>https://dev.to/addwebsolutionpvtltd/getting-started-with-laravel-api-resources-for-clean-json-responses-in-laravel-525m</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;“Clean code always looks like it was written by someone who cares.”&lt;br&gt;
-- Michael Feathers&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;API Resources format and clean your JSON responses.&lt;/li&gt;
&lt;li&gt;They help separate transformation logic from controller logic.&lt;/li&gt;
&lt;li&gt;Supports nested relationships and conditional fields.&lt;/li&gt;
&lt;li&gt;You can disable default data wrapping.&lt;/li&gt;
&lt;li&gt;Adds meta information like API version easily.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Index
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;What is a Resource?&lt;/li&gt;
&lt;li&gt;Creating a Resource&lt;/li&gt;
&lt;li&gt;make() vs collection()&lt;/li&gt;
&lt;li&gt;Loading Relationships with Resources&lt;/li&gt;
&lt;li&gt;Hiding Data with Resources&lt;/li&gt;
&lt;li&gt;Best Practices&lt;/li&gt;
&lt;li&gt;Interesting Facts&lt;/li&gt;
&lt;li&gt;FAQ’s&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. What is a Resource?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Resource&lt;/strong&gt; in Laravel is a way to transform your Eloquent models into a customized array or JSON structure. It allows you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hide sensitive fields&lt;/li&gt;
&lt;li&gt;Format data (e.g., timestamps)&lt;/li&gt;
&lt;li&gt;Include related models (relationships)&lt;/li&gt;
&lt;li&gt;Maintain consistency in API responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Default JSON without resource:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "id": 1,
  "name": "John",
  "email": "john@example.com",
  "email_verified_at": "2024-01-01",
  "created_at": "2024-01-01T00:00:00.000000Z",
  "updated_at": "2024-01-01T00:00:00.000000Z"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;With a resource:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "id": 1,
  "name": "John"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Creating a Resource
&lt;/h2&gt;

&lt;p&gt;Generate a resource with Artisan:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:resource UserResource

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

&lt;/div&gt;



&lt;p&gt;It creates a file in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app/Http/Resources/UserResource.php
namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' =&amp;gt; $this-&amp;gt;id,
            'name' =&amp;gt; $this-&amp;gt;name,
            'email' =&amp;gt; $this-&amp;gt;email,
        ];
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use it in a controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use App\Http\Resources\UserResource;
use App\Models\User;

public function show($id)
{
    return new UserResource(User::findOrFail($id));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. make() vs collection()
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Using &lt;code&gt;make()&lt;/code&gt; for a Single Model&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Controller:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function show($id)
{
    $user = User::findOrFail($id);
    return UserResource::make($user);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "id": 1,
  "name": "John Doe",
  "email": "john@example.com"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Using &lt;code&gt;collection()&lt;/code&gt; for Multiple Models&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Controller:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function index()
{
    $users = User::all();
    return UserResource::collection($users);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
  {
    "id": 1,
    "name": "John Doe",
    "email": "john@example.com"
  },
  {
    "id": 2,
    "name": "Jane Doe",
    "email": "jane@example.com"
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;make()&lt;/strong&gt; → single object&lt;br&gt;
&lt;strong&gt;collection()&lt;/strong&gt; → list of objects&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Loading Relationships with Resources
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Example: User has one Profile&lt;/strong&gt;&lt;br&gt;
User.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function profile()
{
    return $this-&amp;gt;hasOne(Profile::class);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Profile.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function user()
{
    return $this-&amp;gt;belongsTo(User::class);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create ProfileResource&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:resource ProfileResource
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ProfileResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'bio' =&amp;gt; $this-&amp;gt;bio,
            'twitter' =&amp;gt; $this-&amp;gt;twitter,
        ];
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Include Profile in UserResource&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use App\Http\Resources\ProfileResource;

class UserResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' =&amp;gt; $this-&amp;gt;id,
            'name' =&amp;gt; $this-&amp;gt;name,
            'email' =&amp;gt; $this-&amp;gt;email,
            'profile' =&amp;gt; new ProfileResource($this-&amp;gt;whenLoaded('profile')),
        ];
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Controller:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function show($id)
{
    $user = User::with('profile')-&amp;gt;findOrFail($id);
    return UserResource::make($user);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "id": 1,
  "name": "John Doe",
  "email": "john@example.com",
  "profile": {
    "bio": "Developer at Example",
    "twitter": "@johndoe"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without &lt;strong&gt;with(‘profile’)&lt;/strong&gt; in controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
{
  "id": 1,
  "name": "John Doe",
  "email": "john@example.com",
  "profile": null
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why use &lt;strong&gt;whenLoaded()&lt;/strong&gt; ?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prevents &lt;strong&gt;unnecessary DB queries&lt;/strong&gt; (lazy loading)&lt;/li&gt;
&lt;li&gt;Allows &lt;strong&gt;optional inclusion&lt;/strong&gt; of relationships based on controller logic&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Hiding Data with Resources
&lt;/h2&gt;

&lt;p&gt;Let’s say we want to hide the user’s password and timestamps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function toArray($request)
{
    return [
        'id'   =&amp;gt; $this-&amp;gt;id,
        'name' =&amp;gt; $this-&amp;gt;name,
        // Email is optional
        'email' =&amp;gt; $this-&amp;gt;when(request()-&amp;gt;user()-&amp;gt;isAdmin(), $this-&amp;gt;email),
    ];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when()&lt;/li&gt;
&lt;li&gt;mergeWhen()&lt;/li&gt;
&lt;li&gt;whenLoaded() for relationships&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;“Creativity is thinking up new things. Innovation is doing new things.”&lt;br&gt;
-- Theodore Levitt&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  6. Best Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use resources for APIs, not inside Blade views.&lt;/li&gt;
&lt;li&gt;Keep transformations lightweight and readable.&lt;/li&gt;
&lt;li&gt;Use nested resources for relationships.&lt;/li&gt;
&lt;li&gt;Use whenLoaded() to avoid empty/null relationship issues.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;“Success is the sum of small efforts, repeated day in and day out.”&lt;br&gt;
-- Robert Collier&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  7. Interesting Facts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You can nest as many resource layers as needed. (&lt;a href="https://laravel.com/docs/12.x/eloquent-resources#nested-resources" rel="noopener noreferrer"&gt;Laravel API Resources - Nested Resources&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Can be reused between web and API if structured correctly. (&lt;a href="https://laravel.com/docs/12.x/eloquent-resources" rel="noopener noreferrer"&gt;Laravel API Resources Overview&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Works well with Laravel Pagination for out-of-the-box data/links/meta output. (&lt;a href="https://laravel.com/docs/12.x/eloquent-resources#paginated-responses" rel="noopener noreferrer"&gt;Laravel Pagination with Resources&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. FAQ’s
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: Should I use Resources in internal tools?&lt;/strong&gt;&lt;br&gt;
A: Yes, if they’re API-driven. It keeps things consistent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Can I return extra metadata?&lt;/strong&gt;&lt;br&gt;
A: Yes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return (new UserResource($user))-&amp;gt;additional([
    'meta' =&amp;gt; ['version' =&amp;gt; '1.0.0']
]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Q: Can I use a resource without a model?&lt;/strong&gt;&lt;br&gt;
A: Yes, you can wrap any array of data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return JsonResource::make([
    'message' =&amp;gt; 'Success',
    'data'    =&amp;gt; [...]
]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  9. Conclusion
&lt;/h2&gt;

&lt;p&gt;Laravel API Resources provide a powerful and clean way to structure JSON responses in APIs. They make your controllers leaner, your API more consistent, and your data transformation more manageable. Use them to deliver beautiful, reliable API output every time.&lt;/p&gt;

&lt;p&gt;About the Author: &lt;em&gt;Vatsal is a web developer at &lt;a href="https://www.addwebsolution.com/our-capabilities/laravel-development-agency" rel="noopener noreferrer"&gt;AddWebSolution&lt;/a&gt;. Building web magic with Laravel, PHP, MySQL, Vue.js &amp;amp; more.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>restapi</category>
      <category>json</category>
    </item>
    <item>
      <title>When to Use Gates, Policies, and the Spatie Permission Package in Laravel</title>
      <dc:creator>Vatsal Acharya</dc:creator>
      <pubDate>Thu, 10 Jul 2025 11:48:57 +0000</pubDate>
      <link>https://dev.to/addwebsolutionpvtltd/when-to-use-gates-policies-and-the-spatie-permission-package-in-laravel-3c56</link>
      <guid>https://dev.to/addwebsolutionpvtltd/when-to-use-gates-policies-and-the-spatie-permission-package-in-laravel-3c56</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;“Good code is its own best documentation.”&lt;br&gt;
&lt;strong&gt;— Steve McConnell&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Key Takeaways
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Learn what &lt;strong&gt;Gates, Policies,&lt;/strong&gt; and &lt;strong&gt;Spatie Permission&lt;/strong&gt; are.&lt;/li&gt;
&lt;li&gt;Understand &lt;strong&gt;when&lt;/strong&gt; to choose each.&lt;/li&gt;
&lt;li&gt;See &lt;strong&gt;step-by-step examples&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Apply everything in &lt;strong&gt;one clear practical scenario&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Index
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;What is Authorization in Laravel?&lt;/li&gt;
&lt;li&gt;When Should You Use Gates?&lt;/li&gt;
&lt;li&gt;When Should You Use Policies?&lt;/li&gt;
&lt;li&gt;When Should You Use Spatie Permission?&lt;/li&gt;
&lt;li&gt;Example Code: Gates&lt;/li&gt;
&lt;li&gt;Example Code: Policies&lt;/li&gt;
&lt;li&gt;Example Code: Spatie Permission&lt;/li&gt;
&lt;li&gt;Practical Example: A Blogging Platform&lt;/li&gt;
&lt;li&gt;Stats&lt;/li&gt;
&lt;li&gt;Interesting Facts&lt;/li&gt;
&lt;li&gt;FAQs&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. What is Authorization in Laravel?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Authorization&lt;/strong&gt; determines what a user can do — unlike authentication (who the user is).&lt;/p&gt;

&lt;p&gt;Laravel provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gates&lt;/strong&gt; (simple closures to allow/deny actions)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policies&lt;/strong&gt; (classes that group rules for a model)&lt;/li&gt;
&lt;li&gt;Integration with packages like &lt;strong&gt;Spatie Permission&lt;/strong&gt; for advanced role and permission management.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. When Should You Use Gates?
&lt;/h3&gt;

&lt;p&gt;Use &lt;strong&gt;Gates&lt;/strong&gt; when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need quick, simple checks.&lt;/li&gt;
&lt;li&gt;Your rule doesn’t depend on Eloquent models.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
“Is the user an admin?”&lt;br&gt;
“Does the user have a verified email?”&lt;/p&gt;
&lt;h3&gt;
  
  
  3. When Should You Use Policies?
&lt;/h3&gt;

&lt;p&gt;Use &lt;strong&gt;Policies&lt;/strong&gt; when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your rules are about a &lt;strong&gt;specific model&lt;/strong&gt; (like Post, Order, Product).&lt;/li&gt;
&lt;li&gt;You want organized, reusable logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
“Does this user own this post?”&lt;br&gt;
“Can the user delete this order?”&lt;/p&gt;
&lt;h3&gt;
  
  
  4. When Should You Use Spatie Permission?
&lt;/h3&gt;

&lt;p&gt;Use &lt;strong&gt;Spatie Permission&lt;/strong&gt; when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want &lt;strong&gt;Role-Based Access Control (RBAC)&lt;/strong&gt; or &lt;strong&gt;Permission-Based Access Control&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You need to manage roles and permissions dynamically (e.g., via an admin UI).&lt;/li&gt;
&lt;li&gt;Your app has multiple user types (admins, editors, moderators, etc).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  5. Example Code: Gates
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;How to define a Gate:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;AuthServiceProvider.php:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Illuminate\Support\Facades\Gate;

public function boot()
{
  $this-&amp;gt;registerPolicies();
  Gate::define('access-admin', function ($user) {
    return $user-&amp;gt;is_admin;
  });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How to use:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (Gate::allows('access-admin')) {
  // Allow
} else {
  abort(403);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Blade:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@can('access-admin')
  &amp;lt;a href="/admin"&amp;gt;Admin Dashboard&amp;lt;/a&amp;gt;
@endcan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Example Code: Policies
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Generate a Policy:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:policy PostPolicy - model=Post

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Define logic:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function update(User $user, Post $post)
{
  return $user-&amp;gt;id === $post-&amp;gt;user_id;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How to use:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$this-&amp;gt;authorize('update', $post);

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

&lt;/div&gt;



&lt;p&gt;In Blade:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@can('update', $post)
  &amp;lt;button&amp;gt;Edit Post&amp;lt;/button&amp;gt;
@endcan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. Example Code: Spatie Permission
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Installation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require spatie/laravel-permission

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan vendor:publish - provider="Spatie\Permission\PermissionServiceProvider"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan migrate

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Assign Roles &amp;amp; Permissions:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;

$permission = Permission::create(['name' =&amp;gt; 'edit articles']);
$role = Role::create(['name' =&amp;gt; 'admin']);
$role-&amp;gt;givePermissionTo('edit articles');
$user-&amp;gt;assignRole('admin');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;In Controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if ($user-&amp;gt;can('edit articles')) {
  // Allow
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Blade:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@can('edit articles')
  &amp;lt;button&amp;gt;Edit Article&amp;lt;/button&amp;gt;
@endcan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  8. Practical Example: A Blogging Platform
&lt;/h3&gt;

&lt;p&gt;Let’s see &lt;strong&gt;the same scenario implemented with each method, so you get a side-by-side comparison.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;&lt;br&gt;
Users can create posts.&lt;br&gt;
Each post has an author_id.&lt;br&gt;
Only the &lt;strong&gt;author or an admin&lt;/strong&gt; can &lt;strong&gt;delete&lt;/strong&gt; a post.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Your work is going to fill a large part of your life, so love what you do.”&lt;br&gt;
&lt;strong&gt;— Steve Jobs&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;With Gates&lt;/strong&gt;&lt;br&gt;
Definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Gate::define('delete-post', function ($user, $post) {
  return $user-&amp;gt;id === $post-&amp;gt;user_id || $user-&amp;gt;is_admin;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (Gate::allows('delete-post', $post)) {
  $post-&amp;gt;delete();
} else {
  abort(403);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Blade:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@can('delete-post', $post)
  &amp;lt;button&amp;gt;Delete Post&amp;lt;/button&amp;gt;
@endcan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;With Policies&lt;/strong&gt;&lt;br&gt;
Generate Policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan make:policy PostPolicy - model=Post

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

&lt;/div&gt;



&lt;p&gt;Define in Policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function delete(User $user, Post $post)
{
  return $user-&amp;gt;id === $post-&amp;gt;user_id || $user-&amp;gt;is_admin;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$this-&amp;gt;authorize('delete', $post);
$post-&amp;gt;delete();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Blade:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@can('delete', $post)
  &amp;lt;button&amp;gt;Delete Post&amp;lt;/button&amp;gt;
@endcan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;With Spatie Permission&lt;/strong&gt;&lt;br&gt;
Setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require spatie/laravel-permission

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan vendor:publish - provider="Spatie\Permission\PermissionServiceProvider"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assign Role and Permission:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$permission = Permission::create(['name' =&amp;gt; 'delete posts']);
$role = Role::create(['name' =&amp;gt; 'admin']);
$role-&amp;gt;givePermissionTo('delete posts');
$user-&amp;gt;assignRole('admin');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if ($user-&amp;gt;can('delete posts')) {
  $post-&amp;gt;delete();
} else {
  abort(403);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Blade:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@can('delete posts')
  &amp;lt;button&amp;gt;Delete Post&amp;lt;/button&amp;gt;
@endcan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;“Software innovation, like almost every other kind of innovation, requires the ability to collaborate and share ideas.”&lt;br&gt;
&lt;strong&gt;— Bill Gates&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  9. Stats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Spatie Permission &amp;gt;10 million downloads (&lt;a href="https://packagist.org/packages/spatie/laravel-permission" rel="noopener noreferrer"&gt;Spatie Laravel Permission on Packagist&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Gates and Policies have been part of Laravel since version 5.1, first released in June 2015. (&lt;a href="https://laravel.com/docs/5.1/authorization" rel="noopener noreferrer"&gt;Authorization — Laravel 5.1&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  10. Interesting Facts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Gates can be registered anywhere — but best in AuthServiceProvider.(&lt;a href="https://laravel.com/docs/12.x/authorization#gates" rel="noopener noreferrer"&gt;Laravel Authorization Docs&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Policies auto-discovered by Laravel. (&lt;a href="https://laravel.com/docs/12.x/authorization#policy-auto-discovery" rel="noopener noreferrer"&gt;Laravel Policy Auto-Discovery&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Spatie Permission caches permissions (php artisan permission:cache-reset).(&lt;a href="https://spatie.be/docs/laravel-permission/v6/introduction" rel="noopener noreferrer"&gt;Spatie Laravel Permission Docs&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  11. FAQs
&lt;/h2&gt;

&lt;p&gt;Q: Can I mix Gates, Policies, and Spatie?&lt;br&gt;
A: Yes — many projects use them together.&lt;/p&gt;

&lt;p&gt;Q: Are Policies required for Spatie?&lt;br&gt;
A: No — but you can combine them.&lt;/p&gt;

&lt;h2&gt;
  
  
  12. Conclusion
&lt;/h2&gt;

&lt;p&gt;Here’s a recap:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gates:&lt;/strong&gt; Small, quick checks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policies:&lt;/strong&gt; Organized model rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spatie Permission:&lt;/strong&gt; Powerful RBAC and permissions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;About the Author: &lt;em&gt;Vatsal is a web developer at &lt;a href="https://www.addwebsolution.com/our-capabilities/laravel-development-agency" rel="noopener noreferrer"&gt;AddWebSolution&lt;/a&gt;. Building web magic with Laravel, PHP, MySQL, Vue.js &amp;amp; more. Blending code, coffee, and creativity to bring ideas to life.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>authorization</category>
      <category>rbac</category>
      <category>permissions</category>
    </item>
  </channel>
</rss>
