ویژگی‌های جدید در نسخه ۱۹ React

React یکی از محبوب‌ترین کتابخانه‌های UI در دنیای توسعه فرانت‌اند است. در این مقاله قصد داریم تا درمورد ویژگی‌های جدید نسخه ۱۹ React صحبت کنیم.

بررسی اجمالی ویژگی‌های جدید React 19

در این بخش یک مرور سریع بر روی ویژگی‌های جدیدی که در نسخه React 19 معرفی شده‌اند خواهیم داشت. سپس در ادامه مقاله هر مورد را به صورت کامل بررسی خواهیم کرد.

  1. React compiler: تیم React در حال کار بر روی پیاده‌سازی یک کامپایلر جدید است. در حال حاضر اینستاگرام از این فناوری استفاده می‌کند و در نسخه‌های بعدی React منتشر خواهد شد.
  2. Server componentها: React مفهوم server componentها را پس از سال‌ها توسعه، معرفی کرده است. اکنون می‌توانیم از این ویژگی با Next.js استفاده نماییم.
  3. Actionها: actionها نحوه تعامل ما با المنت‌های DOM را متحول خواهند کرد.
  4. Document Metadata: این مورد یکی دیگر از بهبودهای بسیار مهم است که به توسعه‌دهندگان این امکان را می‌دهد تا با کد کم‌تر، کارهای بیشتری انجام دهند.
  5. Assets Loading: این ویژگی امکانی را فراهم می‌کند تا assetهای برنامه در پس‌زمینه لود شوند. همین موضوع باعث می‌شود که هم زمان بارگذاری برنامه و هم تجربه کاربری بهبود پیدا کند.
  6. Web componentها: این یک ویژگی بسیار جالب است زیرا، نسخه ۱۹ React توسعه‌دهندگان را قادر می‌سازد تا web componentها را باهم ترکیب نمایند. به این ترتیب امکانات بی‌شماری در اختیار آن‌ها قرار می‌گیرد.
  7. هوک‌های پیشرفته: هوک‌های جدیدی در این نسخه وجود دارند که می‌توانند تجربه کدنویسی ما را متحول کنند.

React 19 قرار است یکی از چالش‌های دیرینه React، یعنی مسئله رندر بیش از حد را حل کند. توسعه‌دهندگان در طول تاریخ ساعت‌های زیادی را صرف رسیدگی به این موضوع کرده‌اند که اغلب منجر به ایجاد مشکلات عملکرد در برنامه می‌شود.

پیش از این، توسعه‌دهندگان برای مدیریت rendering به استفاده از تکنیک‌هایی مانند useMemo()، useCallback()، memo و غیره متکی بودند. اما با React 19، چنین مداخلات دستی دیگر لازم نخواهد بود.

این فریم‌ورک به طور هوشمند کدهای پس‌زمینه را شناسایی کرده و به حافظه می‌سپارد و در نتیجه کدهای تمیزتر و کارآمدتر به دست می‌آید.

React compiler

در حال حاضر، React در صورت تغییر state، به‌طور خودکار رندر مجدد نمی‌شود. یک راه برای بهینه‌سازی این رندرها استفاده دستی از هوک‌های useMemo()، useCallback() و APIهای memo است. اما تیم React متوجه شد که بهینه‌سازی دستی چندان مناسب نیست و باعث سردرگمی می‌شود. به این ترتیب، اقدام به حل این مشکل کردند.

در نتیجه، تیم React کامپایلر React را ساخت. کامپایلر React اکنون این رندرها را مدیریت خواهد کرد. React به طور خودکار تصمیم می‌گیرد که چگونه و چه زمانی state را تغییر دهد و رابط کاربری را به‌روزرسانی نماید. با این کار، دیگر نیازی نیست که توسعه‌دهندگان این کار را به صورت دستی انجام دهند. همچنین دیگر نیازی به استفاده از useMemo()، useCallback() و memo وجود ندارد.

Server componentها

تا به اکنون، کامپوننت‌های React عمدتاً در سمت کلاینت اجرا می‌شدند. اما React در حال معرفی مفهوم پیشگامانه اجرای کامپوننت‌ها در سمت سرور است.

ایده server component سال‌هاست که در جریان بوده و Next.js در پیاده‌سازی آن برای تولید، پیشگام بوده است. با معرفی نسخه Next.js 13، همه کامپوننت‌ها به طور پیش‌فرض server component هستند. برای اجرای یک کامپوننت در سمت کلاینت، باید از دستور use client استفاده کنیم.

در نسخه React 19، سرورکامپوننت‌ها مستقیماً در React ادغام می‌شوند و مزایای زیادی را به همراه خواهند داشت که عبارتند از:

  • سئو: کامپوننت‌های رندر شده توسط سرور با ارائه محتوای قابل دسترس‌تر برای crawlerهای وب، بهینه‌سازی موتور جستجو را افزایش می‌دهند.
  • تقویت عملکرد: server componentها به لود سریع‌تر صفحه اولیه و بهبود عملکرد کلی برنامه کمک می‌کنند. این موضوع به ویژه برای برنامه‌هایی که محتوای زیاد و سنگینی دارند بسیار مفید می‌باشد.
  • اجرای سمت سرور: server componentها اجرای کد بر روی سرور را فعال می‌کنند و کارهایی مانند فراخوانی‌های API را بدون مشکل و به صورت کارآمد انجام می‌دهند.

این مزایا بر روی توانایی server componentها برای ایجاد تحول بزرگ در توسعه وب مدرن تاکید می‌کنند.

تمام کامپوننت‌های موجود در React به طور پیش‌فرض سمت کلاینت هستند. اما زمانی که از use server استفاده کنیم، کامپوننتی که داریم یک server component خواهد بود.

به عنوان مثال، کد زیر در React است اما روی سرور اجرا خواهد شد. ما فقط باید use server را به خط اول کامپوننت اضافه کنیم و آن را به یک server component تبدیل نماییم. این کامپوننت دیگر در سمت کلاینت اجرا نمی‌شود و فقط در سمت سرور اجرا می‌شود.

چگونه می‌توانیم از یک server component استفاده کنیم؟

ما می‌توانیم requestUsername را در هر کامپوننت React در همان پروژه import کنیم. پس از این که server component را در هر کامپوننتی که می‌خواهیم import کردیم، می‌توانیم از Actions (که در بخش بعدی با آن آشنا می‌شویم) برای انجام یک کار خاص استفاده نماییم.

'use server';

export default async function requestUsername(formData) {
  const username = formData.get('username');
  if (canRequest(username)) {
    // ...
    return 'successful';
  }
  return 'failed';
}

در حال حاضر Next.js از کامپوننت سمت سرور پشتیبانی می‌کند. با استفاده از نسخه React 19، پشتیبانی از server componentها مستقیماً در React در دسترس خواهد بود.

Actionها

یکی دیگر از ویژگی‌های مهمی که در نسخه ۱۹ به React اضافه شده است مبحث Actionها می‌باشد.

Actionها این امکان را به ما می‌دهند که actionها را با تگ HTML <form/> ادغام کنیم. به عبارت ساده‌تر، می‌توانیم event onSubmit را با Actionها جایگزین نماییم. این Actionها جزو ویژگی‌های فرم HTML هستند.

قبل از Actionها:

در قطعه کد زیر از event onSubmit استفاده می‌کنیم، که پس از submit کردن فرم، اجرای متد search را آغاز می‌کند. اما توجه به این نکته مهم است که در حال حاضر، متد search فقط در سمت کلاینت اجرا می‌شود. در این حالت، ما محدود به استفاده از eventهای React برای submit کردن فرم هستیم، به این معنی که search در سمت سرور قابل اجرا نیست.

<form onSubmit={search}>
  <input name="query" />
  <button type="submit">Search</button>
</form>

بعد از Actionها:

با معرفی server componentها می‌توانیم Actionها را در سمت سرور اجرا کنیم. در این حالت می‌توانیم داخل تگ <form/> که در JSX داریم به جای event onSubmit از ویژگی action استفاده نماییم. مقدار ویژگی action متدی برای ارسال داده‌ها در سمت کلاینت یا سرور خواهد بود.

ما می‌توانیم عملیات synchronous و asynchronous، ساده‌سازی مدیریت ارسال داده‌ها و به‌روزرسانی‌های state را با استفاده از actionها اجرا کنیم. هدف این است که کار با فرم‌ها و مدیریت داده‌ها آسان‌تر شود. به عنوان مثال:

"use server"

const submitData = async (userData) => {
    const newUser = {
        username: userData.get('username'),
        email: userData.get('email')
    }
    console.log(newUser)
}
const Form = () => {
    return <form action={submitData}>
        <div>
            <label>Name</label>
            <input type="text" name='username'/>
        </div>
        <div>
            <label>Name</label>
            <input type="text" name="email" />
        </div>
        <button type='submit'>Submit</button>
    </form>
}

export default Form;

در کد بالا، submitData در واقع action در server component است. form یک کامپوننت سمت کلاینت است که از submitData به عنوان action استفاده می‌کند. submitData بر روی سرور اجرا خواهد شد. ارتباط کامپوننت‌های کلاینت(form) و سرور (submitData) فقط به دلیل ویژگی action امکان‌پذیر می‌باشد.

ما می‌توانیم از فرم و action برای handle کردن ارسال داده در سمت کلاینت و همچنین در سمت سرور استفاده کنیم.

Web componentها

Web componentها این امکان را به ما می‌دهند که کامپوننت‌های سفارشی را با استفاده از HTML، CSS و جاوااسکریپت native ایجاد کرده و آن‌ها را به صورت یکپارچه و همانند تگ‌های استاندارد HTML در برنامه‌های وب خود مورد استفاده قرار دهیم.

در حال حاضر، ادغام web componentها در React کار ساده‌ای نیست. به طور معمول، یا باید web component را به کامپوننت React تبدیل کنیم و یا این که پکیج‌های اضافی نصب کرده و کدهایی بنویسیم تا web componentها با React کار کنند. این کار می‌تواند کمی پیچیده باشد.

خوشبختانه، React 19 به ما کمک می‌کند تا web componentها را بسیار راحت‌تر در کد React خود ادغام نماییم. اگر با یک web component واقعاً مفید مانند carousel مواجه شدیم، می‌توانیم بدون این که نیاز باشد آن را به کد React تبدیل کنیم، آن را به طور یکپارچه در پروژه‌های React خود بگنجانیم.

این امر توسعه را ساده‌تر می‌کند و به ما این امکان را می‌دهد تا از اکوسیستم گسترده web componentها موجود در برنامه‌های React خود استفاده کنیم. اما در حال حاضر، جزئیات بیشتری در مورد اینکه کد چه ظاهری دارد در دسترس نمی‌باشد.

Document Metadata

المنت‌هایی مانند title، تگ‌های meta و description در بهینه‌سازی سئو و تضمین دسترسی بسیار مهم هستند. در React، جایی که برنامه‌های تک صفحه‌ای(SPA) رایج هستند، مدیریت این المنت‌ها در مسیرهای مختلف می‌تواند کمی دردسرساز باشد.

در حال حاضر، توسعه‌دهندگان اغلب به نوشتن کد سفارشی یا استفاده از پکیج‌هایی مانند react-helmet برای مدیریت تغییرات مسیر و به‌روزرسانی metadataها متوسل می‌شوند. این فرآیند می‌تواند تکراری و مستعد خطا باشد، به‌ویژه زمانی که با المنت‌های حساس به سئو مانند تگ‌های meta سروکار داریم.

قبل از document metadata:

import React, { useEffect } from 'react';

const HeadDocument = ({ title }) => {
  useEffect(() => {
    document.title = title;

 	const metaDescriptionTag = document.querySelector('meta[name="description"]');
    if (metaDescriptionTag) {
    metaDescriptionTag.setAttribute('content', 'New description');
    }
  }, [title]);

  return null;
};

export default HeadDocument;

در کد بالا یک کامپوننت HeadDocument داریم که وظیفه به‌روزرسانی title و تگ‌های meta را بر اساس props دارد. ما این‌ها را در هوک useEffect به‌روزرسانی می‌کنیم. همچنین از جاوااسکریپت برای به‌روزرسانی title و تگ‌های meta استفاده می‌نماییم. این کامپوننت در هنگام تغییر مسیر به‌روزرسانی می‌شود، اما روش درستی برای انجام این کار نیست.

بعد از document metadata:

با استفاده از React 19، می‌توانیم از title و تگ‌های meta مستقیماً در کامپوننت‌های React استفاده کنیم:

Const HomePage = () => {
  return (
    <>
      <title>Freecodecamp</title>
      <meta name="description" content="Freecode camp blogs" />
      // Page content
    </>
  );
}

قبلاً در React این امکان وجود نداشت. تنها راه حل، استفاده از پکیجی مانند react-helmet بود.

همچنین می‌توانیم با مطالعه این منابع، اطلاعات بیشتری درمورد link، meta، script، style و title کسب کنیم.

Asset Loading

در React، باید تجربه لود و عملکرد برنامه‌های خود را به‌ویژه در مورد تصاویر و سایر فایل‌های asset به دقت مدیریت نماییم.

اغلب موارد، ابتدا view در مرورگر رندر می‌شود و سپس stylesheetها، فونت‌ها و تصاویر قرار می‌گیرند. این موضوع می‌تواند منجر به سوسو زدن از محتوای بدون استایل به view استایل‌شده شود.

برای کاهش این مشکل، توسعه‌دهندگان اغلب به افزودن کد سفارشی متوسل می‌شوند تا تشخیص دهند که این assetها چه زمانی آماده هستند، و اطمینان حاصل کنند که view تنها پس از لود شدن همه موارد نمایش داده می‌شود.

در React 19، تصاویر و سایر فایل‌ها در پس‌زمینه لود می‌شوند، زیرا کاربران صفحه فعلی را کاوش می‌کنند. این بهبود باید به بهبود زمان بارگذاری صفحه و کاهش دوره انتظار کمک کند.

همچنین، React برای لود کردن assetها، از جمله اسکریپت‌ها، stylesheetها و فونت‌ها چرخه حیات Suspense را معرفی می‌کند. این ویژگی React را قادر می‌سازد تا تعیین کند که محتوا چه زمانی برای نمایش آماده است و هرگونه سوسو زدن بدون استایل را حذف می‌کند.

APIهای Resource Loading جدیدی مانند preload و preinit وجود دارند تا کنترل بیشتری برای زمان بارگیری و راه‌اندازی یک resource فراهم کنند.

React 19 با اجازه دادن به assetها برای لود asynchronously در پس‌زمینه، زمان انتظار را به حداقل می‌رساند و تضمین می‌کند که کاربران می‌توانند بدون وقفه با محتوا تعامل داشته باشند. این بهینه‌سازی نه تنها عملکرد برنامه‌های React را افزایش می‌دهد، بلکه تجربه مرور لذت‌بخش‌تری را برای کاربران فراهم می‌نماید.

هوک‌های جدید React

هوک‌های React یکی از محبوب‌ترین ویژگی‌های معرفی شده در این کتابخانه هستند. احتمالاً بارها از هوک‌های داخلی React در پروژه‌های خود استفاده کرده‌ایم، و یا شاید سعی کرده‌ایم تا هوک‌های سفارشی خود را نیز بسازیم. هوک‌ها آنقدر محبوب هستند که به یک الگوی برنامه نویسی React تبدیل شده‌اند.

در React 19، نحوه استفاده از هو‌ک‌های useMemo، forwardRef، useEffect و useContext تغییر خواهد کرد. این موضوع عمدتا به این دلیل است که یک هوک جدید با نام use معرفی خواهد شد.

هوک useMemo()

بعد از React 19 دیگر نیازی به استفاده از هوک useMemo() نخواهیم داشت، زیرا React Compiler خودبه‌خود عمل به حافظه سپردن را انجام می‌دهد.

حالت قبل:

import React, { useState, useMemo } from 'react';

function ExampleComponent() {
  const [inputValue, setInputValue] = useState('');

  // Memoize the result of checking if the input value is empty
  const isInputEmpty = useMemo(() => {
    console.log('Checking if input is empty...');
    return inputValue.trim() === '';
  }, [inputValue]);

  return (
    <div>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
        placeholder="Type something..."
      />
      <p>{isInputEmpty ? 'Input is empty' : 'Input is not empty'}</p>
    </div>
  );
}

export default ExampleComponent;

حالت بعد:

در مثال زیر، می‌بینیم که بعد از React 19، نیازی به به خاطر سپردن مقادیر نداریم، زیرا React در نسخه ۱۹ به تنهایی این کار را در پس‌زمینه انجام می‌دهد. در نتیجه کد بسیار تمیزتری خواهیم داشت:

import React, { useState, useMemo } from 'react';

function ExampleComponent() {
  const [inputValue, setInputValue] = useState('');

  const isInputEmpty = () => {
    console.log('Checking if input is empty...');
    return inputValue.trim() === '';
  });

  return (
    <div>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
        placeholder="Type something..."
      />
      <p>{isInputEmpty ? 'Input is empty' : 'Input is not empty'}</p>
    </div>
  );
}

export default ExampleComponent;

هوک forwardRef()

ref اکنون به‌جای استفاده از هوک forwardRef()، به عنوان props ارسال می‌شود. این کار کد را ساده‌تر می‌کند. بنابراین پس از React 19، دیگر نیازی به استفاده از هوک forwardRef() نخواهیم داشت.

حالت قبل:

در مثال زیر نحوه استفاده از هوک forwardRef() قبل از React 19 را داریم:

import React, { forwardRef } from 'react';

const ExampleButton = forwardRef((props, ref) => (
  <button ref={ref}>
    {props.children}
  </button>
));

حالت بعد:

ref را می‌توانیم به عنوان یک prop ارسال کنیم. بنابراین دیگر نیازی به استفاده از هوک forwardRef() وجود ندارد.

import React from 'react';

const ExampleButton = ({ ref, children }) => (
  <button ref={ref}>
    {children}
  </button>
);

هوک جدید use()

React 19 یک هوک جدید به نام use() معرفی خواهد کرد. این هوک نحوه استفاده از promiseها، کدهای async و context را ساده‌تر می‌کند.

سینتکس هوک use() به صورت زیر می‌باشد:

const value = use(resource);

کد زیر نمونه‌ای از نحوه استفاده از هوک use برای درخواست fetch می‌باشد:

import { use } from "react";

const fetchUsers = async () => {
    const res = await fetch('https://jsonplaceholder.typicode.com/users');
    return res.json();
  };
  
  const UsersItems = () => {
    const users = use(fetchUsers());
  
    return (
      <ul>
        {users.map((user) => (
          <div key={user.id} className='bg-blue-50 shadow-md p-4 my-6 rounded-lg'>
            <h2 className='text-xl font-bold'>{user.name}</h2>
            <p>{user.email}</p>
          </div>
        ))}
      </ul>
    );
  }; 
export default UsersItems;

کدی که داریم به این صورت است که:

  • fetchUsers مسئول درخواست GET است.
  • ما به جای استفاده از useEffect یا useState، از هوک use برای اجرای fetchUsers استفاده می‌کنیم.
  • مقدار بازگشتی هوک useState برابر با users است که response درخواست GET را خواهند داشت(users).
  • در بلاک return، ما از users برای map کردن بر روی آن و ایجاد لیست استفاده می‌کنیم.

کد کامل مثال در این لینک گیت‌هاب در دسترس می‌باشد.

مکان دیگری که می‌توانیم از هوک جدید استفاده کنیم، Context است. Context API یک روش محبوب برای مدیریت stateهای سراسری در React بدون استفاده از هیچ کتابخانه مدیریت state می‌باشد. با استفاده از هوک use، هوک context مانند کد زیر خواهد بود.

حال به جای useContext()، ما use(context) را خواهیم داشت.

import { createContext, useState, use } from 'react';

const ThemeContext = createContext();

const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState('light');

  const toggleTheme = () => {
    setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

const Card = () => {
  // use Hook()
  const { theme, toggleTheme } = use(ThemeContext);

  return (
    <div
      className={`p-4 rounded-md ${
        theme === 'light' ? 'bg-white' : 'bg-gray-800'
      }`}
    >
      <h1
        className={`my-4 text-xl ${
          theme === 'light' ? 'text-gray-800' : 'text-white'
        }`}
      >
        Theme Card
      </h1>
      <p className={theme === 'light' ? 'text-gray-800' : 'text-white'}>
       Hello!! use() hook
      </p>
      <button
        onClick={toggleTheme}
        className='bg-blue-500 hover:bg-blue-600 text-white rounded-md mt-4 p-4'
      >
        {theme === 'light' ? 'Switch to Dark Mode' : 'Switch to Light Mode'}
      </button>
    </div>
  );
};

const Theme = () => {
  return (
    <ThemeProvider>
      <Card />
    </ThemeProvider>
  );
};

export default Theme

کدی که داریم کارهای زیر را انجام می‌دهد:

  • ThemeProvider مسئول ارائه context است.
  • card کامپوننتی است که در آن context را مورد استفاده قرار می‌دهیم. برای این کار از هوک جدید use استفاده می‌کنیم. بقیه موارد همانند قبل از React 19 می‌باشد.

کد کامل مثال در این لینک گیت‌هاب در دسترس می‌باشد.

در React 19، هوک‌های جدیدی برای handle کردن وضعیت فرم‌ها و داده‌ها داریم که کار با آن‌ها را راحت‌تر می‌کند. همینطور ترکیب این هوک‌ها با actionها، که ویژگی جدید نسخه ۱۹ React است، کار با فرم‌ها و مدیریت داده‌ها را آسان‌تر می‌کند.

هوک useFormStatus()

هوک useFormStatus() یک هوک جدید در React 19 است که به ما کمک می‌کند تا کنترل بیشتری بر روی فرم‌هایی که ایجاد می‌کنیم داشته باشیم. این هوک اطلاعات وضعیت آخرین فرم ارسالی را به ما رائه می‌دهد. سینتکس آن به صورت زیر است:

const { pending, data, method, action } = useFormStatus();

یا ورژن ساده‌تر آن که به شکل زیر می‌باشد:

const { status } = useFormStatus()

در سینتکس این هوک:

  • pending: اگر state فرم در حالت pending باشد true و در غیر این صورت false خواهد بود.
  • data: آبجکتی است که FormData interface را پیاده‌سازی می‌کند و حاوی داده‌هایی می‌باشد که <form>parent آن را ارسال می‌کند.
  • method: شامل متدهای HTTP یعنی GET و یا POST می‌باشد. به طور پیش‌فرض مقدار آن GET خواهد بود.
  • action: یک تابع reference است.

این هوک برای نمایش state pending و اینکه چه داده‌هایی توسط کاربر ارسال می‌شود مورد استفاده قرار می‌گیرد. به عنوان مثال:

import { useFormStatus } from "react-dom";

function Submit() {
  const status = useFormStatus();
  return <button disabled={status.pending}>{status.pending ? 'Submitting...' : 'Submit'}</button>;
}

const formAction = async () => {
  // Simulate a delay of 2 seconds
  await new Promise((resolve) => setTimeout(resolve, 3000));
}

const FormStatus = () => {
  return (
    <form action={formAction}>
      <Submit />
    </form>
  );
};

export default FormStatus;

کاری که کد بالا انجام می‌دهد عبارتند از:

  • Submit یک متد است؛ یک action فرم برای submit کردن فرم. این متد status را از useFormStatus بررسی می‌کند و به ما اطلاع می‌دهد که آیا status.pending دارای مقدار true است یا false.
  • بر اساس status.pending می‌توانیم پیام را در رابط کاربری نمایش دهیم.
  • formAction یک متد فیک برای به تاخیر انداختن ارسال فرم است.

کد بالا، در submission فرم از هوک useFormStatus وضعیت pending را دریافت می‌کند. در حالی که pending مقدار true دارد، متن Submitting... در رابط کاربری نمایش داده می‌شود. هنگامی که مقدار pending تغییر کرده و false می‌شود، متن ارسال هم به Submitted تغییر پیدا می‌کند.

این هوک بسیار قدرتمند است و زمانی مفید خواهد بود که می‌خواهیم از وضعیت submission فرم، که آیا در حالت pending است یا نه مطلع شویم و بر این اساس داده‌ها را به نمایش بگذاریم.

کد کامل مثال در این لینک گیت‌هاب در دسترس می‌باشد.

هوک useFormState()

یکی دیگر از هوک‌های جدیدی که در نسخه React 19 معرفی شده است هوک useFormState می‌باشد. این هوک به ما این امکان را می‌دهد که وضعیت را بر اساس نتیجه submission فرم به‌روزرسانی کنیم. سینتکس آن به صورت زیر است:

const [state, formAction] = useFormState(fn, initialState, permalink?);
  • fn: تابعی که باید هنگام submit کردن فرم یا کلیک بر روی دکمه فراخوانی شود.
  • initialState: مقداری که می‌خواهیم state در ابتدا داشته باشد را شامل می‌شود و می‌تواند هر مقدار serializable را دربر بگیرد. این آرگومان پس از اولین فراخوانی action نادیده گرفته می‌شود.
  • permalink: این یک آرگومان اختیاری است. یک URL یا لینک صفحه است که اگر قرار باشد fn روی سرور اجرا شود، در این صورت صفحه باید به permalink هدایت شود.

این هوک مقادیر زیر را return می‌کند:

  • state: مقدار state اولیه همان مقداری است که به initialState داده‌ایم.
  • formAction: اکشنی است که به action فرم منتقل می‌شود. مقدار بازگشتی این مورد در state موجود خواهد بود.

در ادامه مثالی از نحوه کارکرد این هوک را بررسی می‌کنیم:

import { useFormState} from 'react-dom';

const FormState = () => {
    const submitForm = (prevState, queryData) => {
        const name =  queryData.get("username");
        console.log(prevState); // previous form state
        if(name === 'john'){
            return {
                success: true,
                text: "Welcome"
            }
        }
        else{
            return {
                success: false,
                text: "Error"
            }
        }
    }
    const [ message, formAction ] = useFormState(submitForm, null)
    return <form action={formAction}>
        <label>Name</label>
        <input type="text" name="username" />
        <button>Submit</button>
        {message && <h1>{message.text}</h1>}
    </form>
}

export default FormState;

در کد بالا:

  • submitForm متدی است که مسئول submission فرم می‌باشد. این متد، action است. ویژگی Action جدید که در نسخه ۱۹ به React اضافه شده است.
  • در داخل submitForm، ما در حال بررسی مقدار فرم هستیم. سپس بسته به موفقیت‌آمیز بودن آن یا نشان دادن خطا، مقدار و پیام خاص را return می‌کنیم. در مثال بالا، اگر مقدار دیگری غیر از John وجود داشته باشد، یک خطا برمی‌گرداند.
  • همچنین می‌توانیم prevState فرم را بررسی کنیم. state اولیه null خواهد بود و پس از آن، prevState فرم را return می‌کند.

هنگام اجرای این مثال، اگر نام John باشد، پیام welcome را خواهیم دید، در غیر این صورت error را return خواهد کرد.

کد کامل مثال در این لینک گیت‌هاب در دسترس می‌باشد.

هوک useOptimistic()

طبق اسناد React، هوک useOptimistic یکی از هوک‌های React است که به ما این امکان را می‌دهد تا state متفاوتی را در حین انجام یک اکشن async نشان دهیم.

این هوک به بهبود تجربه کاربر کمک می‌کند و باید منجر به پاسخ‌های سریع‌تر شود. هوک useOptimistic همچنین برای برنامه‌هایی که نیاز به تعامل با سرور دارند هم مفید خواهد بود.

سینتکس هوک useOptimistic به شکل زیر می‌باشد:

const [ optimisticMessage, addOptimisticMessage] = useOptimistic(state, updatefn)

به عنوان مثال، در حالی که یک response در راه است، می‌توانیم یک state را نشان دهیم تا به کاربر یک response فوری بدهیم. هنگامی که response واقعی از سرور return شود، حالت optimistic با آن جایگزین می‌شود.

هوک useOptimistic بلافاصله UI را با فرض موفقیت‌آمیز بودن درخواست به‌روزرسانی می‌کند. این نام optimistic است، زیرا کاربر نتیجه optimistic (موفقیت‌آمیز بودن) انجام یک action را می‌بیند، حتی اگر انجام آن action واقعاً به زمان نیاز داشته باشد.

در ادامه بررسی می‌کنیم که چگونه باید این هوک را پیاده‌سازی کنیم. کد زیر state optimistic را با کلیک روی دکمه submit  <form input> (Sending...) نشان می‌دهد تا زمانی که response هنوز نرسیده است.

import { useOptimistic, useState } from "react";

const Optimistic = () => {
  const [messages, setMessages] = useState([
    { text: "Hey, I am initial!", sending: false, key: 1 },
  ]);
  const [optimisticMessages, addOptimisticMessage] = useOptimistic(
    messages,
    (state, newMessage) => [
      ...state,
      {
        text: newMessage,
        sending: true,
      },
    ]
  );

  async function sendFormData(formData) {
    const sentMessage = await fakeDelayAction(formData.get("message"));
    setMessages((messages) => [...messages, { text: sentMessage }]);
  }

  async function fakeDelayAction(message) {
    await new Promise((res) => setTimeout(res, 1000));
    return message;
  }

  const submitData = async (userData) => {
    addOptimisticMessage(userData.get("username"));

    await sendFormData(userData);
  };

  return (
    <>
      {optimisticMessages.map((message, index) => (
        <div key={index}>
          {message.text}
          {!!message.sending && <small> (Sending...)</small>}
        </div>
      ))}
      <form action={submitData}>
        <h1>OptimisticState Hook</h1>
        <div>
          <label>Username</label>
          <input type="text" name="username" />
        </div>
        <button type="submit">Submit</button>
      </form>
    </>
  );
};

export default Optimistic;
  • fakeDelayAction یک متد فیک برای به تاخیر انداختن event submit است. این متد برای نشان دادن state optimistic مورد استفاده قرار می‌گیرد.
  • submitData یک action است. این متد مسئولیت submission فرم را بر عهده دارد که می‌تواند async باشد.
  • sendFormData مسئول ارسال فرم به fakeDelayAction است.
  • تنظیم state پیش‌فرض. messages در useOptimistic() به عنوان ورودی مورد استفاده قرار خواهد گرفت و در optimisticMessagesreturn خواهد شد.
const [messages, setMessages] = useState([{ text: "Hey, I am initial!", sending: false, key: 1 },]);

بیشتر وارد جزئیات می‌شویم:

ما در داخل submitData، از addOptimisticMessage استفاده می‌کنیم. با این کار، داده‌های فرم اضافه می‌شود تا در optimisticMessage در دسترس قرار بگیرند. ما این روش را برای نشان دادن یک پیام در UI به کار خواهیم گرفت:

{optimisticMessages.map((message, index) => (
        <div key={index}>
          {message.text}
          {!!message.sending && <small> (Sending...)</small>}
        </div>
      ))}

کد کامل مثال در این لینک گیت‌هاب در دسترس می‌باشد.

آیا اکنون می‌توانیم از React 19 استفاده کنیم؟

در حال حاضر، تمام ویژگی‌های ذکر شده در این مقاله در canary release موجود است. می‌توانیم از طریق این لینک اطلاعات بیشتری در این زمینه کسب کنیم. همانطور که توسط تیم React پیشنهاد شده است، در حال حاضر نباید از این ویژگی‌های در پروژه‌های واقعی خود استفاده کنیم. برای اطلاع از زمان دقیق انتشار نسخه ۱۹ Reactمی‌توانیم Canary Releases را برای اطلاع از به‌روزرسانی‌ها دنبال کنیم.

جمع‌بندی

ما در این مقاله به بررسی ویژگی‌های جدیدی که در نسخه ۱۹ React به آن اضافه خواهند شد پرداختیم که در ادامه خلاصه‌ای از آن‌ها را باهم مرور می‌کنیم:

  • در نسخه ۱۹ یک React compiler جدید به کتابخانه React اضافه خواهد شد.
  • اکنون در نسخه ۱۹ re-rendering خودکار، memoization و بهینه‌سازی state و رابط کاربری را خواهیم داشت.
  • چند هوک جدید مانند use() در نسخه ۱۹ معرفی خواهد داشت که به ساده‌سازی promiseها و کدهای async کمک می‌کند.
  • در این نسخه پشتیبانی از کامپوننت‌های سمت سرور در React وجود خواهد داشت.
  • با استفاده از actionها، useFormStatus()، useStatusForm() و useOptimistic() مدیریت فرم بهتری خواهیم داشت.
  • React در این نسخه asset loading را برای افزایش عملکرد با استفاده از suspense در پس‌زمینه بهینه خواهد کرد.
  • و درنهایت در نسخه ۱۹ React ما یکپارچه‌سازی web component را خواهیم داشت.

دیدگاه‌ها:

Amir Mohamd Mohamadi

فروردین 28, 1403  در  8:27 ب.ظ

اینکه react هم خودش Server component هارو داشته باشه شاید استفاده از next کمتر بشه ولی مهم ترین نکته اینکه next همیشه خواسته یک قدم جلوتر از react باشه باید ببینیم قدم بعدی next چیه و حالا که داریم next14 رو یاد میگیریم باید به ۱۵ هم فکر کنیم.
حالا سوالی که از استاد صدری عزیز دارم اینکه به نظر شما باید کدوم سمت بریم ؟
این فقط نظر منه و شاید هم اشتباه باشه.

مسعود صدری

فروردین 28, 1403  در  11:07 ب.ظ

سلام
حقیقتش نمی‌تونم یک نظر قطعی در این مورد داشته باشم.
مهم‌ترین دلیل این هست که تیم‌های Next.js و React باهم همکاری دارند.
به نظرم باید ببینیم نسخه‌های بعدی Next.js چطور پیش می‌ره.
البته این رو هم باید در نظر بگیرم که امکان Route Handler و مباحث مربوط به Cache فعلا جز فیچرهای اختصاصی Next.js هست.

افزودن دیدگاه جدید