<?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: Luke</title>
    <description>The latest articles on DEV Community by Luke (@lukewanghanxiang).</description>
    <link>https://dev.to/lukewanghanxiang</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%2F1973397%2Fbd1ea090-387b-4599-b70f-f8b7e06ecf19.jpg</url>
      <title>DEV Community: Luke</title>
      <link>https://dev.to/lukewanghanxiang</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lukewanghanxiang"/>
    <language>en</language>
    <item>
      <title>Easy Todo List App with React and Tailwind CSS</title>
      <dc:creator>Luke</dc:creator>
      <pubDate>Fri, 04 Oct 2024 01:35:37 +0000</pubDate>
      <link>https://dev.to/lukewanghanxiang/easy-todo-list-app-with-react-and-tailwind-css-1j2c</link>
      <guid>https://dev.to/lukewanghanxiang/easy-todo-list-app-with-react-and-tailwind-css-1j2c</guid>
      <description>&lt;p&gt;In this blog post, I'll walk you through the process of building a simple Todo List application using React and TailwindCSS. This project is perfect for beginners who want to dive deeper into React for managing state and learn how to style components using the utility-first CSS framework, TailwindCSS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;p&gt;The goal of this project is to create a basic Todo List where users can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Add new tasks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Toggle tasks between completed and uncompleted.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Delete tasks they no longer need.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ll leverage React’s state management capabilities and style everything using TailwindCSS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step1: Setting up the project
&lt;/h2&gt;

&lt;p&gt;To begin, we’ll set up a React project using &lt;code&gt;create-react-app&lt;/code&gt; and install TailwindCSS.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create React App:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app todo-list
cd todo-list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install TailwindCSS: TailwindCSS needs to be installed along with PostCSS and autoprefixer for automatic browser compatibility.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Configure Tailwind: In tailwind.config.js, update the content section to point to your React app’s files:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  content: ["./src/**/*.{js,jsx,ts,tsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Include Tailwind in your CSS: In &lt;code&gt;src/index.css&lt;/code&gt;, import the TailwindCSS directives:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@tailwind base;
@tailwind components;
@tailwind utilities;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, TailwindCSS is fully integrated into our React app!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Creating the Todo List Component
&lt;/h2&gt;

&lt;p&gt;Next, let's create a Todo List component where users can add, delete, and toggle tasks.&lt;/p&gt;

&lt;p&gt;Here’s the core structure of the &lt;code&gt;TodoList.js&lt;/code&gt; component:&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;TodoList&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;tasks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTasks&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="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;newTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setNewTask&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;addTask&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newTask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setTasks&lt;/span&gt;&lt;span class="p"&gt;([...&lt;/span&gt;&lt;span class="nx"&gt;tasks&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;newTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&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="nf"&gt;setNewTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toggleTaskCompletion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedTasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;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="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;index&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;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedTasks&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;deleteTask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedTasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&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="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedTasks&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;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;max-w-md mx-auto mt-10 p-4 bg-white rounded-lg shadow-lg&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;h1&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="s2"&gt;text-2xl font-bold mb-4&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;Todo&lt;/span&gt; &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&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;div&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="s2"&gt;flex mb-4&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;input&lt;/span&gt;
          &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&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="s2"&gt;flex-1 p-2 border rounded&lt;/span&gt;&lt;span class="dl"&gt;"&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;newTask&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="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setNewTask&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="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Add a new task...&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="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;addTask&lt;/span&gt;&lt;span class="p"&gt;}&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="s2"&gt;ml-2 p-2 bg-blue-500 text-white rounded hover:bg-blue-600&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;Add&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;/div&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;ul&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;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&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;index&lt;/span&gt;&lt;span class="p"&gt;}&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="s2"&gt;flex justify-between items-center mb-2&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;span&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="s2"&gt;`flex-1 &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;line-through text-gray-500&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="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="nx"&gt;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;toggleTaskCompletion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;task&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;/span&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;deleteTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
              &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ml-4 p-1 bg-red-500 text-white rounded hover:bg-red-600&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;Delete&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;/li&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;/ul&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;/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;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;TodoList&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Integrating the Component into the App
&lt;/h2&gt;

&lt;p&gt;Once the TodoList component is ready, integrate it into the main App.js file. Here’s how:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import './App.css';
import TodoList from './components/TodoList';

function App() {
  return (
    &amp;lt;div className="App"&amp;gt;
      &amp;lt;TodoList /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Testing your work!
&lt;/h2&gt;

&lt;p&gt;By running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see the basic layout of our Todo List Page like this:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqzzczofyvss0wn9331ix.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqzzczofyvss0wn9331ix.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Typing your todos:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2g6ynczx07oln66aaolp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2g6ynczx07oln66aaolp.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking the Add button to add the todos:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0cyaxiwc2fppl77mhd1a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0cyaxiwc2fppl77mhd1a.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Toggle the tasks that have been completed:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwyy1bl1xqt142929o3dw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwyy1bl1xqt142929o3dw.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Delete the task that you don't want anymore by clicking the Delete button:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F77q4nvpkibc68ky6civ4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F77q4nvpkibc68ky6civ4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Building this Todo List with React and TailwindCSS helped demonstrate the power of combining a component-based library like React with a utility-first CSS framework. React's state management, combined with Tailwind's simple, intuitive styling, allowed us to quickly create a responsive, interactive application.&lt;/p&gt;

&lt;p&gt;You can continue enhancing this app by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Persisting the tasks in localStorage so they’re saved between page refreshes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Adding due dates or priority levels to tasks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Expanding the design with more complex styles and animations.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading! I hope this project inspired you to explore more with React and TailwindCSS.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>React: Introduction to Hooks for Beginners</title>
      <dc:creator>Luke</dc:creator>
      <pubDate>Thu, 29 Aug 2024 07:09:05 +0000</pubDate>
      <link>https://dev.to/lukewanghanxiang/react-introduction-to-hooks-for-beginners-5672</link>
      <guid>https://dev.to/lukewanghanxiang/react-introduction-to-hooks-for-beginners-5672</guid>
      <description>&lt;h2&gt;
  
  
  What are React Hooks?
&lt;/h2&gt;

&lt;p&gt;React Hooks are special functions that let you use state and other React features in functional components. Introduced in React 16.8, Hooks have fundamentally changed the way developers build components.&lt;/p&gt;

&lt;p&gt;Hooks allow you to "hook into" React’s state and lifecycle features directly from functional components, which were previously only possible in class components.&lt;/p&gt;

&lt;h4&gt;
  
  
  Historical Background
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Class Components Before Hooks:&lt;/strong&gt; Before Hooks, React developers had to rely on class components to manage state and lifecycle methods. This often led to complex, unmanageable code, especially as components grew larger.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Why Hooks Were Introduced:&lt;/strong&gt; Hooks were introduced to solve the common problems associated with class components, such as the difficulties in reusing logic, managing side effects, and dealing with complex lifecycle methods.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why use hooks?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Problems Hooks Solve&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;State Management in Functional Components:&lt;/strong&gt; Previously, functional components were stateless. Hooks enabled them to manage state, making it easier to write simpler, more reusable code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reusing Logic:&lt;/strong&gt; Class components made it difficult to reuse stateful logic across multiple components. With Hooks, you can easily extract and share logic through custom hooks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simplifying Complex Components:&lt;/strong&gt; Hooks help reduce the complexity of components by eliminating the need for lifecycle methods that are spread out across different phases of a component’s life.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cleaner and More Readable Code:&lt;/strong&gt; With Hooks, there’s no need to deal with this keyword, binding issues, or long class hierarchies, making the code more readable and easier to maintain.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Commonly Used Hooks Brief Intro
&lt;/h2&gt;

&lt;h3&gt;
  
  
  useState
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Concept:&lt;/strong&gt; useState is the most basic Hook, allowing you to add state to functional components. It returns an array with the current state and a function to update it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;How It Works:&lt;/strong&gt; When you call useState, React initializes state for the component and preserves it between re-renders.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function Counter() {
  const [count, setCount] = useState(0);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;You clicked {count} times&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setCount(count + 1)}&amp;gt;
        Click me
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use Cases:&lt;/strong&gt; useState is used whenever you need to keep track of a value that can change over time, like form inputs, counters, toggles, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  useEffect
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Concept: useEffect allows you to perform side effects in function components. It combines the functionality of componentDidMount, componentDidUpdate, and componentWillUnmount.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How It Works: useEffect runs after every render by default but can be controlled with a dependency array to run only when certain values change.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function Example() {
  const [count, setCount] = useState(0);

  useEffect(() =&amp;gt; {
    document.title = `You clicked ${count} times`;
  }, [count]); // Only re-run the effect if count changes

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;You clicked {count} times&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setCount(count + 1)}&amp;gt;
        Click me
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;: useEffect is perfect for fetching data, manually updating the DOM, setting up subscriptions, or cleaning up resources when a component unmounts.&lt;/p&gt;

&lt;h3&gt;
  
  
  useContext
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Concept: useContext allows you to access context values directly in your functional components without needing to use the Consumer component.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How It Works: When you call useContext with a context object, React returns the current value of that context.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const ThemeContext = React.createContext('light');

function ThemeButton() {
  const theme = useContext(ThemeContext);

  return &amp;lt;button className={theme}&amp;gt;I am styled by theme context!&amp;lt;/button&amp;gt;;
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;: useContext is used when you need to pass data deeply through the component tree without having to prop-drill, such as theme settings, authenticated user information, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  useReducer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Concept: useReducer is similar to useState, but more powerful in managing complex state logic. It is often used as an alternative to useState when dealing with complex state transitions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How It Works: useReducer takes a reducer function and an initial state, returning the current state and a dispatch function.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;Count: {state.count}&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; dispatch({ type: 'decrement' })}&amp;gt;-&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; dispatch({ type: 'increment' })}&amp;gt;+&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;: useReducer is ideal for managing complex state logic, such as when the state object has multiple sub-values or when the next state depends on the previous one.&lt;/p&gt;

&lt;h2&gt;
  
  
  useRef
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Concept: useRef returns a mutable ref object whose .current property is initialized to the passed argument. It’s primarily used to access DOM elements directly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How It Works: useRef doesn’t cause a re-render when the .current property changes, unlike useState.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () =&amp;gt; {
    // `current` points to the mounted text input element
    inputEl.current.focus();
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;input ref={inputEl} type="text" /&amp;gt;
      &amp;lt;button onClick={onButtonClick}&amp;gt;Focus the input&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;: useRef is useful for accessing and interacting with DOM elements directly, as well as holding mutable values that don’t cause re-renders, like timers or IDs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations and Notice Points of Hooks Usage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Hooks Can Only Be Called in Function Components or Custom Hooks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Limitation: Hooks cannot be used in regular JavaScript functions. They can only be called within React's function components or custom Hook functions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reason: React relies on the order of Hook calls to correctly manage component state and side effects. If Hooks are used in regular functions, React won't be able to track these calls properly, leading to errors or unstable behavior.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Correct
function MyComponent() {
  const [count, setCount] = useState(0);
  // Using useState is allowed
  return &amp;lt;div&amp;gt;{count}&amp;lt;/div&amp;gt;;
}

// Incorrect
function myFunction() {
  const [count, setCount] = useState(0); // Error: Hooks cannot be used in regular functions
}

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Hooks Can Only Be Called at the Top Level
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Limitation: Do not call Hooks inside loops, conditionals, or nested functions. Hooks must be called at the top level of a component or custom Hook.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reason: React relies on the order of Hook calls to manage state correctly. If Hooks are called inside conditionals or loops, the order of calls might change between renders, leading to incorrect state updates.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Correct
function MyComponent() {
  const [count, setCount] = useState(0);

  if (count &amp;gt; 0) {
    // You can use state or call other functions inside conditionals
  }

  return &amp;lt;div&amp;gt;{count}&amp;lt;/div&amp;gt;;
}

// Incorrect
function MyComponent() {
  if (someCondition) {
    const [count, setCount] = useState(0); // Error: Hooks cannot be called inside conditionals
  }

  return &amp;lt;div&amp;gt;{count}&amp;lt;/div&amp;gt;;
}

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Naming Convention for Custom Hooks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Limitation: The name of a custom Hook must start with "use," such as useMyCustomHook.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reason: The "use" prefix lets React know that the function is a custom Hook, allowing it to handle the Hook calls properly. Violating this naming convention might cause the custom Hook not to be recognized correctly.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Be Aware of the Asynchronous Nature of State Updates
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Limitation: State updates are asynchronous, so do not rely on the immediately updated value after a state change.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reason: React batches state updates to improve performance, which may cause delays in state updates. Depending on the immediately updated value may result in outdated data.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function MyComponent() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
    console.log(count); // May log the old value because setCount is asynchronous
  }

  return &amp;lt;button onClick={handleClick}&amp;gt;Click me&amp;lt;/button&amp;gt;;
}

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

&lt;/div&gt;



&lt;p&gt;When using React Hooks, it's essential to adhere to these usage limitations and best practices to ensure your components behave consistently, predictably, and are easy to maintain. Hooks are designed to simplify the development of function components, but improper usage can introduce unexpected issues. Understanding these limitations and avoiding common mistakes will help you use Hooks more effectively and write robust React applications.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>beginners</category>
      <category>learning</category>
    </item>
    <item>
      <title>Javascript: Deep &amp; Shallow Clone Complete Guide</title>
      <dc:creator>Luke</dc:creator>
      <pubDate>Wed, 28 Aug 2024 07:10:25 +0000</pubDate>
      <link>https://dev.to/lukewanghanxiang/javascript-deep-shallow-copy-complete-guide-180o</link>
      <guid>https://dev.to/lukewanghanxiang/javascript-deep-shallow-copy-complete-guide-180o</guid>
      <description>&lt;h2&gt;
  
  
  Shallow Clone
&lt;/h2&gt;

&lt;p&gt;Shallow clone refers to creating a new object that exactly copies the original object's properties. If the copied value is a primitive data type, the value itself is copied. If it's a reference data type, the memory address is copied. &lt;strong&gt;&lt;em&gt;If the memory address of one object changes, the other object will also reflect that change.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  (1) Object.assign()
&lt;/h3&gt;

&lt;p&gt;Object.assign() is a method introduced in ES6 for copying objects. The first parameter is the target object, and the remaining parameters are source objects. The syntax is Object.assign(target, source_1, ...). This method can perform shallow copying and can also perform deep copying of one-dimensional objects.&lt;/p&gt;

&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If the target object and source objects have properties with the same name, or if multiple source objects have properties with the same name, the properties of the latter objects will overwrite those of the former.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the function has only one parameter, and that parameter is an object, it returns the object directly. If the parameter is not an object, it converts the parameter to an object and then returns it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Since null and undefined cannot be converted to objects, the first parameter cannot be null or undefined, or it will throw an error.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let target = {a: 1};
let object2 = {b: 2};
let object3 = {c: 3};
Object.assign(target,object2,object3);  
console.log(target);  // {a: 1, b: 2, c: 3}

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  (2) Spread Operator
&lt;/h3&gt;

&lt;p&gt;The spread operator can be used to copy properties when constructing literal objects. The syntax is: let cloneObj = { ...obj };.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let obj1 = {a: 1, b: {c: 1}};
let obj2 = {...obj1};
obj1.a = 2;
console.log(obj1); // {a: 2, b: {c: 1}}
console.log(obj2); // {a: 1, b: {c: 1}}
obj1.b.c = 2;
console.log(obj1); // {a: 2, b: {c: 2}}
console.log(obj2); // {a: 1, b: {c: 2}}

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  (3) Array Methods for Shallow Copying Arrays
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Array.prototype.slice
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The slice() method is a JavaScript array method that returns selected elements from an existing array. The syntax is array.slice(start, end), and the method does not modify the original array.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The method takes two optional parameters. If neither is provided, the method creates a shallow copy of the array.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let arr = [1, 2, 3, 4];
console.log(arr.slice()); // [1, 2, 3, 4]
console.log(arr.slice() === arr); // false

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Array.prototype.concat
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The concat() method is used to merge two or more arrays. This method does not modify the existing arrays but returns a new array.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The method takes two optional parameters. If neither is provided, the method creates a shallow copy of the array.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let arr = [1, 2, 3, 4];
console.log(arr.concat()); // [1, 2, 3, 4]
console.log(arr.concat() === arr); // false

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  (4) Implementing Shallow Clone
&lt;/h3&gt;

&lt;p&gt;Here is a JavaScript code example to manually implement a shallow copy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Implementation of shallow copy
function shallowClone(object) {
  // Only copy objects
  if (object === null || typeof object !== "object") return object;

  // Determine whether to create a new array or object based on the type of the original object
  let newObject = Array.isArray(object) ? [] : {};

  // Iterate over the original object, and only copy its own properties
  for (let key in object) {
    if (object.hasOwnProperty(key)) {
      newObject[key] = object[key];
    }
  }

  return newObject;
}

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

&lt;/div&gt;



&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Type Checking: The function first checks if the input is an object (not null or a primitive type). If not, it returns itself.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Type Determination: Based on whether the original object is an array or a plain object, the function creates a new array or a new object to hold the copied properties.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Property Copying: The function then iterates over the original object using a for...in loop. It checks if the property is directly on the object (i.e., not inherited) using hasOwnProperty(). If so, it copies the property to the new object.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Return: Finally, the new object (or array) with the copied properties is returned.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Test Case:&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;const original = {
  name: 'Alice',
  age: 25,
  details: {
    city: 'New York'
  },
  hobbies: ['reading', 'swimming']
};

const copy = shallowClone(original);

console.log(copy);
// Output: { name: 'Alice', age: 25, details: { city: 'New York' }, hobbies: ['reading', 'swimming'] }

copy.name = 'Bob';
copy.details.city = 'Los Angeles';
copy.hobbies[0] = 'running';

console.log(original.name); // 'Alice', the basic property of the original object is not modified

console.log(original.details.city); // 'Los Angeles', the reference of the nested object is shared

console.log(original.hobbies[0]); // 'running', the reference of the array elements is shared

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deep Clone
&lt;/h2&gt;

&lt;p&gt;Deep clone, in contrast to shallow clone, &lt;strong&gt;&lt;em&gt;creates a new reference type and copies the corresponding values when encountering properties that are reference types. This means the object obtains a new reference type rather than a reference to the original type.&lt;/em&gt;&lt;/strong&gt; Deep clone can be achieved for some objects using JSON's two functions, but since the JSON format is stricter than the JavaScript object format, it may fail when the property values include functions or Symbol types.&lt;/p&gt;

&lt;h3&gt;
  
  
  (1) JSON.stringify()
&lt;/h3&gt;

&lt;p&gt;JSON.parse(JSON.stringify(obj)) is one of the more commonly used methods for deep copying. Its principle is to use JSON.stringify to serialize the JavaScript object into a JSON string, and then use JSON.parse to deserialize (restore) the JavaScript object.&lt;/p&gt;

&lt;p&gt;This method can achieve deep copying in a simple and straightforward manner, but it has some limitations. If the object being copied contains functions, undefined, Date, RegExp, Map, Set, or Symbol values, these will be lost after processing with JSON.stringify().&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function deepClone(obj) {
  return JSON.parse(JSON.stringify(obj));
}

const original = {
  name: 'Alice',
  age: 25,
  details: {
    city: 'New York',
    hobbies: ['reading', 'swimming']
  }
};

const copy = deepClone(original);

copy.name = 'Bob';
copy.details.city = 'Los Angeles';
copy.details.hobbies[0] = 'running';

console.log(original.name); // 'Alice'
console.log(original.details.city); // 'New York'
console.log(original.details.hobbies[0]); // 'reading'

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  （2）_.cloneDeep provided by Lodash
&lt;/h3&gt;

&lt;p&gt;The lodash library provides the _.cloneDeep method for performing deep copies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const _ = require('lodash');

const original = {
  name: 'Alice',
  age: 25,
  details: {
    city: 'New York',
    hobbies: ['reading', 'swimming'],
    birthDate: new Date('1995-01-01')
  }
};

const copy = _.cloneDeep(original);

copy.name = 'Bob';
copy.details.city = 'Los Angeles';
copy.details.hobbies[0] = 'running';
copy.details.birthDate.setFullYear(2000);

console.log(original.name); // 'Alice'
console.log(original.details.city); // 'New York'
console.log(original.details.hobbies[0]); // 'reading'
console.log(original.details.birthDate.getFullYear()); // 1995
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  (3) structuredClone() global function
&lt;/h3&gt;

&lt;p&gt;structuredClone() is a native JavaScript API used for deep copying. It can clone a JavaScript object and recursively copy all of its nested child objects, rather than just copying references. Compared to traditional deep copy methods, structuredClone() is more powerful and flexible.&lt;/p&gt;

&lt;h5&gt;
  
  
  Features of structuredClone()
&lt;/h5&gt;

&lt;p&gt;Deep Copy: structuredClone() recursively copies an object and all of its nested child objects and arrays, creating a completely new object copy. Modifying the copy does not affect the original object, and vice versa.&lt;/p&gt;

&lt;p&gt;Support for Multiple Data Types: structuredClone() can correctly handle most JavaScript data types, including:&lt;br&gt;
Primitive data types (e.g., strings, numbers, booleans)&lt;br&gt;
Objects and arrays&lt;br&gt;
Date objects&lt;br&gt;
RegExp objects&lt;br&gt;
Map and Set&lt;br&gt;
ArrayBuffer, TypedArray, Blob, File, FileList, and other types&lt;/p&gt;

&lt;p&gt;Unsupported Types: structuredClone() cannot clone the following types:&lt;br&gt;
Functions (Function)&lt;br&gt;
Symbol&lt;br&gt;
Objects with circular references (this will throw an error)&lt;br&gt;
Performance Optimization: Since structuredClone() is natively implemented by the browser, it generally offers better performance and stability compared to manually implemented deep copy methods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const original = {
  name: 'Alice',
  age: 25,
  details: {
    city: 'New York',
    birthDate: new Date('1995-01-01'),
    pattern: /abc/g,
  },
  hobbies: ['reading', 'swimming'],
  nestedArray: [1, [2, 3]],
};

// Perform deep copy using structuredClone
const copy = structuredClone(original);

// Modify the copy
copy.name = 'Bob';
copy.details.city = 'Los Angeles';
copy.hobbies[0] = 'running';
copy.nestedArray[1][0] = 99;

console.log(original.name); // 'Alice'
console.log(original.details.city); // 'New York'
console.log(original.hobbies[0]); // 'reading'
console.log(original.nestedArray[1][0]); // 2

console.log(copy.name); // 'Bob'
console.log(copy.details.city); // 'Los Angeles'
console.log(copy.hobbies[0]); // 'running'
console.log(copy.nestedArray[1][0]); // 99

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

&lt;/div&gt;



&lt;p&gt;structuredClone() is particularly well-suited for the following scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Deep Copying Complex Data Structures: When you need to copy an object that contains nested objects, arrays, or other complex structures, structuredClone() ensures complete independence between the copy and the original object.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoiding the Complexity of Manual Deep Copying: Manually implementing deep copying requires handling various edge cases and data types. structuredClone() provides a native solution that handles these situations more simply and reliably.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  (4) Implementing Deep Clone
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function deepClone(object, hash = new WeakMap()) {
  // Non-object types or null, return directly
  if (object === null || typeof object !== "object") return object;

  // Check for circular references
  if (hash.has(object)) return hash.get(object);

  // Handle special object types
  let newObject;
  if (Array.isArray(object)) {
    newObject = [];
  } else if (object instanceof Date) {
    newObject = new Date(object);
  } else if (object instanceof RegExp) {
    newObject = new RegExp(object);
  } else {
    newObject = {};
  }

  // Record the current object to avoid circular references
  hash.set(object, newObject);

  // Recursively copy all properties
  for (let key in object) {
    if (object.hasOwnProperty(key)) {
      newObject[key] = deepClone(object[key], hash);
    }
  }

  return newObject;
}

// Test example
const original = {
  name: "Alice",
  age: 25,
  details: {
    city: "New York",
    hobbies: ["reading", "swimming"],
    birthDate: new Date("1995-01-01"),
    pattern: /abc/g,
  },
};

// Introduce a circular reference
original.self = original;

const copy = deepCopy(original);

console.log(copy);

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

&lt;/div&gt;



&lt;p&gt;Notice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Return value for non-object types: If object is null or a non-object type (such as string, number, boolean), the function directly returns object. This ensures that the deep copy function returns the original value instead of undefined when encountering non-object types.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Handling circular references: A WeakMap is used to track objects that have already been copied. If the same object is encountered again, the function returns the previously created copy to prevent infinite recursion.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Handling special object types: The function includes special handling for Date and RegExp objects to correctly copy instances of these types. If additional types (e.g., Map, Set) need to be supported, the code can be further extended based on specific requirements.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>React: Understanding React's Event System</title>
      <dc:creator>Luke</dc:creator>
      <pubDate>Tue, 27 Aug 2024 11:08:54 +0000</pubDate>
      <link>https://dev.to/lukewanghanxiang/react-understanding-reacts-event-system-dm7</link>
      <guid>https://dev.to/lukewanghanxiang/react-understanding-reacts-event-system-dm7</guid>
      <description>&lt;h2&gt;
  
  
  Overview of React's Event System
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is a Synthetic Event?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Synthetic events&lt;/strong&gt; are an event-handling mechanism designed by React to achieve cross-browser compatibility, optimize performance, and simplify event handling. &lt;strong&gt;&lt;em&gt;It encapsulates native browser events, providing a unified API and event handling approach, ensuring consistent event behavior across different browsers.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Working Principle of Synthetic Events
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Event Delegation
&lt;/h4&gt;

&lt;p&gt;React handles events through an event delegation mechanism. Event delegation means that React doesn't directly bind event listeners to each DOM element. Instead, it binds all event listeners to a single root node (usually the document or the root container of the application). When a user interacts with the page and triggers an event, the event bubbles up the DOM tree to the root node, where React captures the event and wraps it as a synthetic event.&lt;/p&gt;

&lt;p&gt;Advantages of Event Delegation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance Optimization:&lt;/strong&gt; It reduces the number of event handlers that need to be bound, thereby lowering memory usage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simplified Event Management:&lt;/strong&gt; By managing all events at the root node, React can more efficiently handle event propagation, prevent default behaviors, and perform other event-related operations.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Event Pooling
&lt;/h4&gt;

&lt;p&gt;A key mechanism behind synthetic events is event pooling. Event pooling means that React reuses event objects instead of creating a new event object each time an event is triggered. When an event occurs, React takes an event object from the event pool, initializes it, and passes it to the event handler. After the event handling is complete, the event object is cleaned up and returned to the event pool for reuse in the next event.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advantages of Event Pooling:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Memory Allocation:&lt;/strong&gt; By reusing event objects, React avoids frequent memory allocation and garbage collection operations, which can significantly improve performance, especially for high-frequency events like mouse movements or scrolling.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Lifecycle of Synthetic Events
&lt;/h4&gt;

&lt;p&gt;Due to event pooling, the lifecycle of synthetic events differs from that of native events. Typically, after the event handler function has finished executing, the properties of the synthetic event object are reset to null so that it can be returned to the pool for reuse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Points to Note:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Asynchronous Operations:&lt;/strong&gt; If you need to access the event object within an asynchronous operation, you must call the event.persist() method. This will prevent the event object from being returned to the pool, ensuring that it doesn't get reset during the asynchronous operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  API and Usage of Synthetic Events
&lt;/h2&gt;

&lt;p&gt;The React Synthetic Event API provides a set of interfaces similar to native browser events, which are commonly used in React. Below is a detailed introduction to some frequently used methods and properties, along with examples illustrating their usage scenarios.&lt;/p&gt;

&lt;p&gt;a. preventDefault()&lt;/p&gt;

&lt;p&gt;The preventDefault() method is used to prevent the default behavior of an event. Default behavior refers to the actions that the browser usually performs when an event occurs, such as refreshing the page when a form is submitted or navigating to a new page when a link is clicked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: Preventing the default form submission behavior&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 MyForm() {
  const handleSubmit = e =&amp;gt; {
    e.preventDefault(); // Prevent the default form submission behavior
    console.log('Form submission prevented');
  };

  return (
    &amp;lt;form onSubmit={handleSubmit}&amp;gt;
      &amp;lt;input type="text" name="name" /&amp;gt;
      &amp;lt;button type="submit"&amp;gt;Submit&amp;lt;/button&amp;gt;
    &amp;lt;/form&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;In this example, if preventDefault() is not called, clicking the submit button will trigger the form submission, causing the page to refresh. By calling preventDefault(), the default behavior is prevented, allowing you to customize the form handling logic instead.&lt;/p&gt;

&lt;p&gt;b. stopPropagation()&lt;br&gt;
The stopPropagation() method is used to stop the further propagation of an event. Events typically propagate from the target element where the event was triggered up to its parent elements (event bubbling). By calling stopPropagation(), you can prevent this propagation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: Stopping the propagation of a click event&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 Parent() {
  const handleParentClick = () =&amp;gt; {
    console.log('Parent clicked');
  };

  return (
    &amp;lt;div onClick={handleParentClick}&amp;gt;
      Parent Div
      &amp;lt;Child /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

function Child() {
  const handleChildClick = e =&amp;gt; {
    e.stopPropagation(); // Stop the event from bubbling up to the parent element
    console.log('Child clicked');
  };

  return &amp;lt;button onClick={handleChildClick}&amp;gt;Click Me&amp;lt;/button&amp;gt;;
}

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

&lt;/div&gt;



&lt;p&gt;In this example, clicking the button triggers the click event handler in the Child component. By default, the event would bubble up to the Parent component and trigger its click handler as well. However, by calling stopPropagation() in the Child component, the event bubbling to the Parent is prevented.&lt;/p&gt;

&lt;p&gt;c. target&lt;br&gt;
The target property refers to the actual DOM element that triggered the event. It is commonly used to access the element that initiated the event and to handle logic related to that element.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Example: Accessing the element that triggered the event *&lt;/em&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 MyComponent() {
  const handleClick = e =&amp;gt; {
    console.log('Clicked element:', e.target);
  };

  return (
    &amp;lt;div onClick={handleClick}&amp;gt;
      &amp;lt;button&amp;gt;Button 1&amp;lt;/button&amp;gt;
      &amp;lt;button&amp;gt;Button 2&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;In this example, when either button is clicked, the e.target in the handleClick function will point to the button element that was clicked. The target property is used to identify which specific element was clicked.&lt;/p&gt;

&lt;p&gt;d. currentTarget&lt;br&gt;
The currentTarget property refers to the DOM element to which the event handler is bound. During event handling, regardless of which child element the event bubbles to, currentTarget always points to the element that the event handler is attached to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: Distinguishing between target and currentTarget&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 MyComponent() {
  const handleClick = e =&amp;gt; {
    console.log('Clicked element:', e.target);
    console.log('Event handler bound to:', e.currentTarget);
  };

  return (
    &amp;lt;div onClick={handleClick}&amp;gt;
      &amp;lt;button&amp;gt;Button 1&amp;lt;/button&amp;gt;
      &amp;lt;button&amp;gt;Button 2&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;In this example, when any button is clicked, event.target will point to the button that was clicked, while event.currentTarget will always point to the parent div element where the event handler is bound.&lt;/p&gt;

&lt;p&gt;e. persist()&lt;br&gt;
The persist() method is used to retain the event object, preventing React from reusing it. This method is typically needed in asynchronous operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: Using the event object in an asynchronous operation&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 MyComponent() {
  const handleClick = e =&amp;gt; {
    e.persist(); // Retain the event object

    setTimeout(() =&amp;gt; {
      console.log('Button clicked:', event.target);
    }, 1000);
  };

  return &amp;lt;button onClick={handleClick}&amp;gt;Click Me&amp;lt;/button&amp;gt;;
}

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

&lt;/div&gt;



&lt;p&gt;In this example, because the event object might be reused in asynchronous operations, persist() is called to retain the event object, ensuring that the event properties can be safely accessed in the setTimeout callback.&lt;/p&gt;

&lt;h2&gt;
  
  
  React Synthetic Event Types
&lt;/h2&gt;

&lt;p&gt;React provides various types of synthetic events that cover common user interaction scenarios. Below are some commonly used synthetic event types along with examples:&lt;/p&gt;

&lt;p&gt;a. Mouse Events&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;onClick: Triggered when an element is clicked.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;onDoubleClick: Triggered when an element is double-clicked.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;onMouseDown: Triggered when a mouse button is pressed down on an element.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;onMouseUp: Triggered when a mouse button is released on an element.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;onMouseMove: Triggered when the mouse is moved over an element.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;onMouseEnter: Triggered when the mouse pointer enters the element's area; does not bubble.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;onMouseLeave: Triggered when the mouse pointer leaves the element's area; does not bubble.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example: Using onClick and onMouseMove&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 MouseTracker() {
  const handleMouseMove = e =&amp;gt; {
    console.log(`Mouse position: (${e.clientX}, ${e.clientY})`);
  };

  return (
    &amp;lt;div onMouseMove={handleMouseMove} style={{ height: '200px', border: '1px solid black' }}&amp;gt;
      Move your mouse here
    &amp;lt;/div&amp;gt;
  );
}

function MyApp() {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; console.log('Button clicked!')}&amp;gt;Click Me&amp;lt;/button&amp;gt;
      &amp;lt;MouseTracker /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;In this example, the MouseTracker component logs the mouse position whenever it moves within the div area, while the button in the MyApp component logs a message when clicked.&lt;/p&gt;

&lt;p&gt;b. Keyboard Events&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;onKeyDown: Triggered when a key is pressed down on the keyboard.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;onKeyUp: Triggered when a key is released on the keyboard.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;onKeyPress: Triggered when a key is pressed and held down (deprecated; it is recommended to use onKeyDown instead).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example: Handling the onKeyDown Event&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 KeyHandler() {
  const handleKeyDown = e =&amp;gt; {
    console.log('Key pressed:', e.key);
  };

  return &amp;lt;input type="text" onKeyDown={handleKeyDown} placeholder="Press any key" /&amp;gt;;
}

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

&lt;/div&gt;



&lt;p&gt;In this example, when the user presses any key while focused on the input field, the handleKeyDown function logs the name of the pressed key.&lt;/p&gt;

&lt;p&gt;c. Focus Events&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;onFocus: Triggered when an element gains focus.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;onBlur: Triggered when an element loses focus.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example: Handling onFocus and onBlur 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;function FocusExample() {
  return (
    &amp;lt;input
      onFocus={() =&amp;gt; console.log('Input focused')}
      onBlur={() =&amp;gt; console.log('Input blurred')}
      placeholder="Focus and blur me"
    /&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;In this example, when the input field gains or loses focus, a corresponding message is logged to the console.&lt;/p&gt;

&lt;p&gt;d. Form Events&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;onChange: Triggered when the value of a form control changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;onSubmit: Triggered when a form is submitted.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;onInput: Triggered when the user inputs data (including actions like deleting or pasting).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example: Handling onChange and onSubmit 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;function MyForm() {
  const [value, setValue] = React.useState('');

  const handleChange = e =&amp;gt; {
    setValue(e.target.value);
  };

  const handleSubmit = e =&amp;gt; {
    e.preventDefault();
    console.log('Form submitted with value:', value);
  };

  return (
    &amp;lt;form onSubmit={handleSubmit}&amp;gt;
      &amp;lt;input type="text" value={value} onChange={handleChange} /&amp;gt;
      &amp;lt;button type="submit"&amp;gt;Submit&amp;lt;/button&amp;gt;
    &amp;lt;/form&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;In this example, as the user types into the input field, the handleChange function updates the component's state. When the form is submitted, the handleSubmit function logs the current value of the input field.&lt;/p&gt;

&lt;h2&gt;
  
  
  Differences Between React Events and Regular HTML Events
&lt;/h2&gt;

&lt;p&gt;a. Event Naming&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Native: All lowercase (e.g., onclick).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;React: CamelCase (e.g., onClick).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;b. Event Handler Syntax&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Native events use strings to specify event handlers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;React events use functions as event handlers.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;c. Preventing Default Browser Behavior&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Native: can use 'return false' to prevent the browser's default behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;React: Instead, you must explicitly call preventDefault() to achieve this.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;d. Order of Event Execution&lt;br&gt;
Native events execute first, followed by synthetic events. Synthetic events bubble up and are bound to the document. Therefore, it's advisable to avoid mixing native and synthetic events. If a native event stops propagation, it may prevent the synthetic event from executing because synthetic events rely on bubbling up to the document to execute.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does React Choose Synthetic Events
&lt;/h2&gt;

&lt;p&gt;The reasons React chooses synthetic events include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cross-Browser Consistency:&lt;/strong&gt; Synthetic events abstract away the differences in event handling across various browsers, ensuring consistent behavior across all browsers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance Optimization:&lt;/strong&gt; Event delegation and event pooling significantly reduce the overhead of event handling, improving the application's performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Better Event Management:&lt;/strong&gt; With synthetic events, React can more effectively control event propagation, prevent default behaviors, and closely integrate with React's batch update mechanism for more efficient event handling.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Javascript: Promise Complete Guide</title>
      <dc:creator>Luke</dc:creator>
      <pubDate>Sun, 25 Aug 2024 07:50:24 +0000</pubDate>
      <link>https://dev.to/lukewanghanxiang/javascript-promise-complete-guide-ndi</link>
      <guid>https://dev.to/lukewanghanxiang/javascript-promise-complete-guide-ndi</guid>
      <description>&lt;h2&gt;
  
  
  What is Promise?
&lt;/h2&gt;

&lt;p&gt;Promise is a new solution for asynchronous programming. ES6 has incorporated it into the language standard, unifying its usage and natively providing the Promise object.&lt;/p&gt;

&lt;p&gt;Its introduction greatly improved the predicament of asynchronous programming, avoiding callback hell. It is more reasonable and powerful than traditional solutions like callback functions and events. &lt;/p&gt;

&lt;p&gt;A Promise, simply put, is a constructor that holds the result of an event that will complete in the future (usually an asynchronous operation). Syntactically, a Promise is an object from which asynchronous operation messages can be retrieved. Promise provides a unified API, allowing various asynchronous operations to be handled in the same way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should we use Promise?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It can effectively solve the callback hell problem in ES5 (avoiding deeply nested callback functions).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It follows a unified standard, with concise syntax, strong readability, and maintainability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Promise object provides a simple API, making it more convenient and flexible to manage asynchronous tasks.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Promise's States
&lt;/h2&gt;

&lt;p&gt;When using a Promise, we can classify it into three states:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;pending: Pending. This is the initial state, where the Promise is neither fulfilled nor rejected.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;fulfilled: Fulfilled/Resolved/Successful. When resolve() is executed, the Promise immediately enters this state, indicating that it has been resolved and the task was successfully completed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;rejected: Rejected/Failed. When reject() is executed, the Promise immediately enters this state, indicating that it has been rejected and the task has failed.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When new Promise() is executed, the state of the promise object is initialized to pending, which is its initial state. The content inside the parentheses of the new Promise() line is executed synchronously. Within the parentheses, you can define a function for an asynchronous task, which has two parameters: resolve and reject. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Create a new promise
const promise = new Promise((resolve, reject) =&amp;gt; {
  //promise's state is pending as soon as entering the function
  console.log('Synchronous Operations');
  //Begin to execute asynchronous operations
  if (Success) {
    console.log('success');
    // If successful, execute resolve() to switch the promise's state to Fulfilled
    resolve(Success);
  } else {
    // If failed, excecute reject() to pass the error and switch the state to Rejected
    reject(Failure);
  }
});
console.log('LukeW');

//Execute promise's then()：to manage success and failure situations
promise.then(
  successValue =&amp;gt; {
    // Process promise's fulfilled state
    console.log(successValue, 'successfully callback'); // The successMsg here is the Success in resolve(Success)
  },
  errorMsg =&amp;gt; {
    //Process promise's rejected state
    console.log(errorMsg, 'rejected'); // The errorMsg here is the Failure in reject(Failure)
  }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Basic Usage of Promise
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create a new Promise Object
&lt;/h3&gt;

&lt;p&gt;The Promise constructor takes a function as its parameter, which has two arguments: resolve and reject.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const promise = new Promise((resolve, reject) =&amp;gt; {
  // ... some code
  if (/* Success */){
    resolve(value);
  } else {
    reject(error);
  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Promise.resolve
&lt;/h4&gt;

&lt;p&gt;The return value of Promise.resolve(value) is also a promise object, which can be chained with a .then call. The code is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Promise.resolve(11).then(function(value){
  console.log(value); // print 11
});

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

&lt;/div&gt;



&lt;p&gt;In the resolve(11) code, it will cause the promise object to transition to the resolved state, passing the argument 11 to the onFulfilled function specified in the subsequent .then. A promise object can be created using the new Promise syntax, or by using Promise.resolve(value).&lt;/p&gt;

&lt;h4&gt;
  
  
  Promise.reject
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function testPromise(ready) {
  return new Promise(function(resolve,reject){
    if(ready) {
      resolve("hello world");
    }else {
      reject("No thanks");
    }
  });
};

testPromise(true).then(function(msg){
  console.log(msg);
},function(error){
  console.log(error);
});

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

&lt;/div&gt;



&lt;p&gt;The meaning of the above code is to pass an argument to the testPromise method, which returns a promise object. If the argument is true, the resolve() method of the promise object is called, and the parameter passed to it is then passed to the first function in the subsequent .then, resulting in the output "hello world." If the argument is false, the reject() method of the promise object is called, which triggers the second function in the .then, leading to the output "No thanks."&lt;/p&gt;

&lt;h3&gt;
  
  
  Methods in Promise
&lt;/h3&gt;

&lt;h5&gt;
  
  
  then()
&lt;/h5&gt;

&lt;p&gt;The then method can accept two callback functions as parameters. The first callback function is called when the Promise object's state changes to resolved, and the second callback function is called when the Promise object's state changes to rejected. The second parameter is optional and can be omitted.&lt;/p&gt;

&lt;p&gt;The then method returns a new Promise instance (not the original Promise instance). Therefore, a chained syntax can be used, where another then method is called after the first one.&lt;/p&gt;

&lt;p&gt;When you need to write asynchronous events in sequence, requiring them to be executed serially, you can write them like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let promise = new Promise((resolve,reject)=&amp;gt;{
    ajax('first').success(function(res){
        resolve(res);
    })
})
promise.then(res=&amp;gt;{
    return new Promise((resovle,reject)=&amp;gt;{
        ajax('second').success(function(res){
            resolve(res)
        })
    })
}).then(res=&amp;gt;{
    return new Promise((resovle,reject)=&amp;gt;{
        ajax('second').success(function(res){
            resolve(res)
        })
    })
}).then(res=&amp;gt;{

})

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

&lt;/div&gt;



&lt;h5&gt;
  
  
  catch()
&lt;/h5&gt;

&lt;p&gt;In addition to the then method, a Promise object also has a catch method. This method is equivalent to the second parameter of the then method, pointing to the callback function for reject. However, the catch method has an additional function: if an error occurs or an exception is thrown while executing the resolve callback function, it will not stop the execution. Instead, it will enter the catch method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p.then((data) =&amp;gt; {
     console.log('resolved',data);
},(err) =&amp;gt; {
     console.log('rejected',err);
     }
); 
p.then((data) =&amp;gt; {
    console.log('resolved',data);
}).catch((err) =&amp;gt; {
    console.log('rejected',err);
});

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

&lt;/div&gt;



&lt;h5&gt;
  
  
  all()
&lt;/h5&gt;

&lt;p&gt;The all method can be used to complete parallel tasks. It takes an array as an argument, where each item in the array is a Promise object. When all the Promises in the array have reached the resolved state, the state of the all method will also become resolved. However, if even one of the Promises changes to rejected, the state of the all method will become rejected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let promise1 = new Promise((resolve,reject)=&amp;gt;{
    setTimeout(()=&amp;gt;{
       resolve(1);
    },2000)
});
let promise2 = new Promise((resolve,reject)=&amp;gt;{
    setTimeout(()=&amp;gt;{
       resolve(2);
    },1000)
});
let promise3 = new Promise((resolve,reject)=&amp;gt;{
    setTimeout(()=&amp;gt;{
       resolve(3);
    },3000)
});
Promise.all([promise1,promise2,promise3]).then(res=&amp;gt;{
    console.log(res);
    //result：[1,2,3] 
})

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

&lt;/div&gt;



&lt;p&gt;When the all method is called and successfully resolves, the result passed to the callback function is also an array. This array stores the values from each Promise object when their respective resolve functions were executed, in the order they were passed to the all method.&lt;/p&gt;

&lt;h5&gt;
  
  
  race()
&lt;/h5&gt;

&lt;p&gt;The race method, like all, accepts an array where each item is a Promise. However, unlike all, when the first Promise in the array completes, race immediately returns the value of that Promise. If the first Promise's state becomes resolved, the race method's state will also become resolved; conversely, if the first Promise becomes rejected, the race method's state will become rejected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let promise1 = new Promise((resolve,reject)=&amp;gt;{
    setTimeout(()=&amp;gt;{
       reject(1);
    },2000)
});
let promise2 = new Promise((resolve,reject)=&amp;gt;{
    setTimeout(()=&amp;gt;{
       resolve(2);
    },1000)
});
let promise3 = new Promise((resolve,reject)=&amp;gt;{
    setTimeout(()=&amp;gt;{
       resolve(3);
    },3000)
});
Promise.race([promise1,promise2,promise3]).then(res=&amp;gt;{
    console.log(res);
    //result：2
},rej=&amp;gt;{
    console.log(rej)};
)

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

&lt;/div&gt;



&lt;p&gt;So, what is the practical use of the race method? When you want to do something, but if it takes too long, you want to stop it; this method can be used to solve that problem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Promise.race([promise1,timeOutPromise(5000)]).then(res=&amp;gt;{})

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

&lt;/div&gt;



&lt;h5&gt;
  
  
  finally()
&lt;/h5&gt;

&lt;p&gt;The finally method is used to specify an operation that will be executed regardless of the final state of the Promise object. This method was introduced in the ES2018 standard.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;promise
.then(result =&amp;gt; {···})
.catch(error =&amp;gt; {···})
.finally(() =&amp;gt; {···});

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

&lt;/div&gt;



&lt;p&gt;In the code above, regardless of the final state of the promise, after the then or catch callbacks have been executed, the callback function specified by the finally method will be executed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What exactly does Promise solve?
&lt;/h2&gt;

&lt;p&gt;In work, you often encounter a requirement like this: for example, after sending an A request using AJAX, you need to pass the obtained data to a B request if the first request is successful; you would need to write the code as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let fs = require('fs')
fs.readFile('./a.txt','utf8',function(err,data){
  fs.readFile(data,'utf8',function(err,data){
    fs.readFile(data,'utf8',function(err,data){
      console.log(data)
    })
  })
})

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

&lt;/div&gt;



&lt;p&gt;The above code has the following drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The latter request depends on the success of the previous request, where the data needs to be passed down, leading to multiple nested AJAX requests, making the code less intuitive.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Even if the two requests don't need to pass parameters between them, the latter request still needs to wait for the success of the former before executing the next step. In this case, you also need to write the code as shown above, which makes the code less intuitive.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After the introduction of Promises, the code becomes like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let fs = require('fs')
function read(url){
  return new Promise((resolve,reject)=&amp;gt;{
    fs.readFile(url,'utf8',function(error,data){
      error &amp;amp;&amp;amp; reject(error)
      resolve(data)
    })
  })
}
read('./a.txt').then(data=&amp;gt;{
  return read(data) 
}).then(data=&amp;gt;{
  return read(data)  
}).then(data=&amp;gt;{
  console.log(data)
})

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

&lt;/div&gt;



&lt;p&gt;This way, the code becomes much more concise, solving the problem of callback hell.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
