بخش 5: معرفی React نسخه 18 و تفاوتهای آن با نسخههای قبلی
1. مقدمه کوتاه
React 18 که در مارچ 2022 منتشر شد، یکی از بزرگترین بهروزرسانیهای تاریخ React محسوب میشود.
این نسخه پایهریزی تغییرات بزرگی را انجام داده که قرار است آینده React را شکل دهد؛ مخصوصاً در حوزه عملکرد (Performance) و رندر همزمان (Concurrent Rendering).
2. تعریف و توضیح مفهومی
React 18:
- همان فلسفه و API کلی نسخههای قبلی را حفظ کرده (Props, State, Hooks)
- ولی روش کار موتور رندرینگ را تغییر داده تا قابلیتهای پیشرفتهتری مثل رندر همزمان، Suspense برای دادهها و بهینهسازی خودکار batching فعال شود.
- یعنی شما میتوانید بدون تغییر اساسی کدهای قدیمی، از مزایای بهینهسازیها لذت ببرید.
3. مهمترین تغییرات React 18
3.1. createRoot جایگزین ReactDOM.render
در نسخههای قبلی:
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
در نسخه 18:
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
علت:createRoot
برای فعال کردن قابلیتهای جدید Concurrent Rendering ضروری است.
3.2. Automatic Batching
در React 17 و قبل، batching (تجمیع آپدیتهای State در یک رندر) فقط داخل رویدادهای React انجام میشد.
در React 18، این کار خودکار و در همه حالتها انجام میشود.
مثال قبل از React 18:
setCount(c => c + 1);
setFlag(f => !f);
// دو بار رندر میشود
بعد از React 18:
setCount(c => c + 1);
setFlag(f => !f);
// فقط یک بار رندر، به طور خودکار
3.3. Concurrent Rendering (حالت همزمان)
نسخه 18 یک موتور رندر جدید دارد به نام Concurrent Renderer که اجازه میدهد:
- UI بدون فریز شدن یا لگ کار کند
- آپدیتهای با اولویت کمتر، قطع و جایگزین آپدیتهای با اولویت بالاتر شوند
- به کاربر تجربه روانتری بدهد
3.4. useId Hook
برای تولید IDهای منحصربهفرد که در SSR (Server-Side Rendering) و مشتری (Client) سازگارند.
مثال:
import { useId } from 'react';
function MyForm() {
const id = useId();
return (
<>
<label htmlFor={id}>نام</label>
<input id={id} type="text" />
</>
);
}
3.5. startTransition
برای مشخص کردن آپدیتهایی که کماهمیتتر هستند و اگر لازم بود، میتوان رندر آنها را عقب انداخت.
مثال:
import { useState, startTransition } from 'react';
function SearchComponent() {
const [value, setValue] = useState('');
const [results, setResults] = useState([]);
function handleChange(e) {
const val = e.target.value;
setValue(val);
startTransition(() => {
// این آپدیتها، از نوع غیرضروری هستند
setResults(filterData(val));
});
}
return (
<>
<input value={value} onChange={handleChange} />
{results.map(r => <div key={r}>{r}</div>)}
</>
);
}
3.6. Suspense پیشرفته برای دادهها
قبل از React 18، Suspense بیشتر برای lazy loading کامپوننت استفاده میشد.
در نسخه جدید:
- میتوان آن را برای دادهها هم استفاده کرد.
- ابزارهایی مثل
react-query
و Relay این قابلیت را هماکنون پشتیبانی میکنند.
3.7. بهبود در StrictMode
در React 18، StrictMode دو بار mount/unmount را در حالت توسعه اجرا میکند تا مشکلات side-effect شناسایی شود. این برای آمادهسازی migration به concurrent rendering است.
4. مثال عملی: پروژه کوچک با قابلیتهای React 18
App.jsx
import { useState, useId, startTransition } from "react";
const data = ["Ali", "Sara", "Reza", "Mina", "Hasan", "Sahar"];
export default function App() {
const [filter, setFilter] = useState('');
const [results, setResults] = useState(data);
const inputId = useId();
const handleChange = (e) => {
const val = e.target.value;
setFilter(val);
startTransition(() => {
setResults(data.filter(name => name.toLowerCase().includes(val.toLowerCase())));
});
};
return (
<div>
<label htmlFor={inputId}>جستجو</label>
<input id={inputId} value={filter} onChange={handleChange} />
<ul>
{results.map((name) => <li key={name}>{name}</li>)}
</ul>
</div>
);
}
5. تحلیل کد
- useId: تضمین میکند که لیبل و ورودی حتی در SSR هم با هم همخوانی داشته باشند.
- startTransition: جستجو در لیست داده، کاری کماولویت است، بنابراین میتوان آن را به صورت همزمان و بدون لگ برای تایپ انجام داد.
- Automatic Batching: بروزرسانی stateها بدون چندین رندر اضافی.
6. تغییرات مهم برای مهاجرت از نسخههای قبلی
- جایگزینی
ReactDOM.render
باcreateRoot
. - بررسی استفاده از
startTransition
در آپدیتهای کماهمیت. - سازگاری با StrictMode جدید.
- استفاده از قابلیتهای بهینه شده Suspense.
7. اشتباهات رایج مبتدیان
- فکر کردن اینکه React 18 همهچیز را بهطور جادویی سریعتر میکند؛ در واقع باید قابلیتها را فعال و درست استفاده کرد.
- نادیده گرفتن تغییرات در
createRoot
. - استفاده نامناسب از
startTransition
برای کارهای ضروری (که باعث کاهش UX میشود). - انتظار داشتن از
useId
برای تولید uuid رندوم (در حالی که فقط برای یکپارچگی ID است).
8. تمرینهای پیشنهادی
- یک فرم با چند فیلد ورودی بسازید که همه IDها با useId ساخته شوند.
- یک لیست بزرگ را با startTransition فیلتر کنید تا تفاوت روان بودن را احساس کنید.
- پروژهای که با React 17 نوشتهاید را به نسخه 18 مهاجرت دهید.
9. جمعبندی
- React 18 پایهگذار رندر همزمان است که آینده رابطهای کاربری را شکل میدهد.
- تغییر اصلی در
createRoot
و قابلیتهای جدید مثلstartTransition
،useId
و Automatic Batching است. - برای استفادهی کامل از مزایا، باید مفاهیم concurrent rendering را یاد بگیرید.