نحوه استفاده از Axios با React

مقدمه
Axios درخواستهای API در React را ساده میکند؛ و در مقایسه با API بومی Fetch، سینتکس بهتر، مدیریت خطای داخلی و Interceptorهایی ارائه میدهد. این آن را به انتخابی محبوب برای توسعهدهندگانی تبدیل میکند که به دنبال Fetch کردن داده با Axios در React هستند. در این آموزش Axios در React، مثالهای عملی از نحوه Fetch کردن داده با Axios در اپلیکیشنهای React را میبینید.
Axios مبتنی بر Promise است؛ که به شما توانایی بهرهگیری از async و await جاوااسکریپت برای کد غیرهمگامِ خواناتر را میدهد.
همچنین میتوانید درخواستها را Intercept و Cancel کنید؛ و محافظت داخلی سمت کلاینت در برابر جعل درخواست بین-سایتی (CSRF) وجود دارد.
در این مقاله، مثالهایی از نحوه استفاده از Axios برای دسترسی به API محبوب JSONPlaceholder درون اپلیکیشن React را میبینید.
Axios در مقابل Fetch: مقایسه سریع
انتخاب بین Axios و API بومی Fetch، نقطه تصمیم رایجی برای توسعهدهندگان React است. این بخش مقایسه کنار-همی فراهم میکند تا روشن کند چرا بسیاری از تیمها Axios را در محیطهای پروداکشن ترجیح میدهند؛ و همزمان مواردی را که Fetch برای پروژههای کوچکتر کافی است بیان میکند.
| ویژگی | Axios | API مربوط به Fetch |
|---|---|---|
| سینتکس | Axios سینتکس تمیز و مبتنی بر Promiseای فراهم میکند که بهطور قابل توجهی کد Boilerplate را کم میکند. توسعهدهندگان میتوانند سریعاً درخواستها را زنجیر کنند، پاسخها را مدیریت و پیکربندیهای سراسری تنظیم کنند. این رویکرد سادهشده نگهداشتن مدیریت API سازگار بین اپلیکیشنهای React متوسط و بزرگ را برای تیمها آسانتر میکند. | Fetch رابط سطح-پایینی با سینتکس پرحرفتر ارائه میدهد. توسعهدهندگان باید هدرها را دستی پیکربندی، JSON را پارس و کدهای وضعیت را برای هر درخواست چک کنند. هرچند در مرورگر داخلی است و نصبی لازم ندارد، اغلب به کد تکراری در پروژههای React بزرگتر منجر میشود. |
| مدیریت خطا | Axios بهطور خودکار برای کدهای پاسخ HTTP خارج از بازه 2xx خطا پرتاب میکند. اشیاء خطای تفصیلی با ویژگیهای response، request و message فراهم میکند؛ که دیباگ را آسانتر میسازد. مدیریت خطای داخلی تضمین میکند توسعهدهندگان سریع مسائل را شناسایی و رفع کنند بدون نوشتن چکهای شرطی تکراری. | Fetch فقط برای خرابیهای سطح-شبکه Promise را Reject میکند. خطاهای HTTP مثل 404 یا 500 بهعنوان Promiseهای Resolve-شده رفتار میشوند و چکهای وضعیت دستی لازم دارند. توسعهدهندگان باید صریحاً بر اساس response.ok خطا پرتاب کنند؛ که به Boilerplate بیشتر و شانس افزایشیافته مدیریت خطای ناسازگار در اپلیکیشنها منجر میشود. |
| Interceptorها | Axios شامل Interceptorهای درخواست و پاسخ است؛ که به توسعهدهندگان اجازه تزریق Tokenهای احراز هویت، ثبت لاگ فعالیت یا تبدیل داده بهصورت سراسری قبل از رسیدن به کامپوننتها را میدهد. این قابلیت بهویژه در اپلیکیشنهای سازمانی ارزشمند است؛ جایی که مدیریت متمرکز درخواست، امنیت، مقیاسپذیری و بهرهوری توسعهدهنده را بین تیمها بهبود میبخشد. | Fetch قابلیت Interceptor داخلی فراهم نمیکند. برای رسیدن به نتایج مشابه، توسعهدهندگان باید Fetch را در توابع Utility سفارشی یا Middleware بپیچند. این پیچیدگی را زیاد، نگهداریپذیری را کم و تبدیلهای متمرکز درخواست یا تزریق Token احراز هویت را در اپلیکیشنهای React بزرگتر چالشبرانگیزتر میکند. |
| مدیریت JSON | Axios پاسخهای JSON را خودکار تبدیل میکند؛ و نیاز به پارس دستی .json() را حذف میکند. این مدیریت داده را ساده و خطای توسعهدهنده را کمینه میکند؛ که به تیمها اجازه تمرکز روی منطق اپلیکیشن بهجای پارس تکراری را میدهد. مدیریت خودکار JSON، Axios را بهویژه در اپلیکیشنهای React پُر-داده جذاب میکند. | Fetch نیازمند پارس دستی JSON با .json() است. این قدم اضافه، Boilerplate را زیاد و ریسک خطا را معرفی میکند اگر توسعهدهندگان پارس کردن یا زنجیر کردن درست Promiseها را فراموش کنند. هرچند برای اپهای کوچک سرراست است، در پروژههای React بزرگتر تکراری و مستعد خطا میشود. |
| لغو درخواست | Axios لغو درخواست را بهصورت نیتیو از طریق API مربوط به CancelToken و یکپارچهسازی جدیدتر AbortController پشتیبانی میکند. این برای اپهای Reactی با وضعیتهای UI داینامیک ضروری است؛ جایی که ممکن است لازم باشد درخواستها Abort شوند—مانند جستجوی زنده یا Unmount شدن کامپوننتها؛ که کارایی و تجربه کاربر را بهبود میبخشد. | Fetch لغو را از طریق API مربوط به AbortController پشتیبانی میکند. اما راهاندازی و یکپارچهسازی دستی لازم دارد؛ که آن را کمتر شهودی از Axios میکند. توسعهدهندگان اغلب باید کد اضافی برای مدیریت مؤثر لغوها بنویسند؛ که در اپلیکیشنهای React پیچیدهٔ مدیریتکننده درخواستهای موازی متعدد میتواند دشوار باشد. |
نکات کلیدی
- Axios تجربه توسعهدهنده برتری نسبت به Fetch ارائه میدهد: Axios سینتکس تمیزتر و مبتنی بر Promiseای فراهم میکند که Boilerplate را کم، پاسخهای JSON را خودکار پارس و مدیریت خطای داخلی برای کدهای وضعیت HTTP شامل میشود. این آن را برای اپلیکیشنهای React متوسط و بزرگ ایدهآل میسازد. در مقابل، API بومی Fetch سبک و داخلی است؛ اما چکهای وضعیت دستی، پارس JSON و فقدان قابلیتهایی مثل Interceptorها لازم دارد؛ که آن را برای ابزارهای کوچک یا موارد استفاده ساده مناسبتر میسازد.
- الگوهای جامع درخواست با مثالهای دنیای واقعی: این راهنما ساخت درخواستهای GET، POST و DELETE با هر دو کامپوننت کلاسی React و Hookها را مرور میکند. هر مثال نشان میدهد چطور وضعیتهای Loading و Error را مدیریت، UI را واکنشگرا بهروزرسانی و درخواستهای در-جریان را برای جلوگیری از نشت حافظه یا بهروزرسانیهای ناخواسته وضعیت بعد از Unmount لغو کنید.
- پیکربندی متمرکز و Interceptorها برای احراز هویت و تلهمتری: با ساخت Instance مشترک Axios و ثبت Interceptorهای درخواست و پاسخ، میتوانید Tokenهای احراز هویت (مثل
Authorization: Bearer <token>) را خودکار الصاق، IDهای همبستگی برای ردیابی اضافه و مدیریت خطا را در کل اپتان نرمال کنید. این امنیت، قابلیت مشاهده و گزارش خطای سازگار تضمین و جریانهای پیشرفتهای مثل Refresh خودکار Token و Retry روی خطاهای 401 را ممکن میسازد. - async/await برای کد خوانا و قابل نگهداری: بهرهگیری از async/await با Axios، منطق غیرهمگام را از-بالا-به-پایین نگه میدارد و مدیریت خطا را با بلاکهای try/catch صریح میسازد. این رویکرد بهطور طبیعی با Hookهای React مثل useEffect و useState یکپارچه میشود؛ و به کد Fetch کردن داده خواناتر، قابل نگهداریتر و مقاومتر در برابر باگ منجر میشود.
- مدیریت خطای مقاوم برای تجربیات کاربر انعطافپذیر: مقاله تشریح میکند چطور بر اساس err.response (خطاهای HTTP)، err.request (خطاهای شبکه) و err.message (راهاندازی/تایماوت) شاخه ببندید تا پیامهای UI کاربرپسند فراهم، جزئیات تشخیصی را برای توسعهدهندگان لاگ و Retryها یا جریانهای جایگزین را پیاده کنید. متمرکز کردن مدیریت خطا تضمین میکند کاربران بازخورد شفاف و قابل-اقدام ببینند و اطلاعات حساس هرگز در UI افشا نشوند.
- الگوهای پیشرفته Axios برای الزامات دنیای واقعی: فراتر از CRUD پایه، Axios موارد استفاده پیشرفتهای مثل Fetch کردن داده صفحهبندیشده با پارامترهای Query، درخواستهای همزمان با Promise.all، آپلود فایل با ردیابی پیشرفت از طریق onUploadProgress و مدیریت Timeout سفارشی را پشتیبانی میکند. این قابلیتها به شما اجازه اپلیکیشنهای React در-سطح-سازمانی بسازید که مقیاسپذیر، کارآمد و کاربرپسندند.
- بهترین روشها برای اپهای React قابل نگهداری: راهنما بر جداسازی منطق API از کامپوننتهای UI، ساخت Hookهای قابل استفاده مجدد (مثل useAxios) و همیشه لغو کردن درخواستها هنگام Unmount تأکید دارد. همچنین پوشش میدهد کِی Axios را بهجای Fetch انتخاب کنیم، چطور پاسخها و خطاها را در TypeScript تایپ کنیم و چطور از دامهای امنیتی رایج مثل افشای Tokenها یا Stack Traceها در UI اجتناب کنیم.
نیاز به دیپلوی پروژه React و زنده داشتنش دارید؟ پلتفرم اپ پارمین کلود را ببینید و پروژه React را مستقیماً از گیتهاب در چند دقیقه دیپلوی کنید.
پیشنیازها
برای دنبال کردن این مقاله به این موارد نیاز دارید:
- Node.js نسخه 20.x (آخرین LTS) نصبشده روی کامپیوترتان. برای نصب روی macOS یا اوبونتو، مراحل راهنماهای «نصب Node.js روی macOS» یا «نصب Node.js روی اوبونتو» در پارمین کلود را دنبال کنید.
- پروژه React جدید راهاندازیشده با Create React App یا مستندات رسمی React برای شروع پروژهها. این مقاله از React نسخه 18.x—آخرین نسخه پایدار—استفاده میکند.
- Axios نصبشده از طریق npm (
npm install axios)—این مقاله نحوه نصب و استفاده از آن را در پروژههای React نشان میدهد. مثالهای اینجا با Axios نسخه 1.x تست شدهاند. برای مستندات و بهروزرسانیها مخزن گیتهاب Axios را ببینید. - npm نسخه v10.x (همراه Node.js 20.x عرضه میشود) یا Yarn بهعنوان مدیر پکیجتان.
- درک پایهای از جاوااسکریپت—که میتوانید با سری «نحوه کدنویسی در جاوااسکریپت» در پارمین کلود بسازید—بههمراه دانش پایه HTML و CSS.
این آموزش با Node.js v20.11.1، npm v10.2.4، react v18.2.0 و axios v1.6.x اعتبارسنجی شده است.
گام ۱ — افزودن Axios به پروژه
حالا یاد میگیرید چطور Axios را در React نصب و به پروژهای که با دنبال کردن راهنمای «راهاندازی پروژه React با Create React App» ساختهاید اضافه کنید:
npx create-react-app react-axios-example
برای افزودن Axios به پروژه، ترمینالتان را باز و به دایرکتوری پروژه بروید:
cd react-axios-example
سپس این دستور را برای نصب Axios اجرا کنید:
npm install axios
yarn add axios
هر دو npm و Yarn آخرین نسخه پایدار Axios را نصب میکنند؛ و تضمین میکنند پروژهتان از بهروزترین قابلیتها و وصلههای امنیتی استفاده کند.
در یک نگاه — گام ۱ (نصب Axios)
- هدف: نصب Axios و تأیید در دسترس بودنش برای اپتان.
- اجرا:
npm install axios(یاyarn add axios).- تأیید:
npm list axios← نسخهای مثل axios@1.x نشان میدهد.cat package.json← وابستگیها شامل"axios": "^1.x".- افزودن
import axios from 'axios'به فایلی؛ سرور توسعه باید بدون خطا کامپایل شود.
خروجی مورد انتظار:
$ npm list axios
project@1.0.0 /path/to/project
└── axios@1.6.x
چکلیست پیادهسازی (درخواست GET):
[ ] Axios با npm/yarn نصب شد
[ ] در package.json تأیید شد
[ ] قادر به import کردن axios بدون خطای بیلد
گام ۲ — مثال درخواست GET با Axios در React
در این مثال، کامپوننت جدیدی میسازید و Axios را درونش Import میکنید تا درخواست GETای بفرستد.
درون پروژه React خودتان، باید کامپوننت جدیدی به نام PersonList بسازید.
اول، زیردایرکتوری جدید components را در دایرکتوری src بسازید:
mkdir src/components
در این دایرکتوری، PersonList.js را بسازید و کد زیر را به کامپوننت اضافه کنید:
src/components/PersonList.js
import React from 'react';
import axios from 'axios';
export default class PersonList extends React.Component {
state = {
persons: []
}
componentDidMount() {
axios.get(`https://jsonplaceholder.typicode.com/users`)
.then(res => {
const persons = res.data;
this.setState({ persons });
})
.catch(err => {
console.error('Error fetching data:', err);
});
}
render() {
return (
<ul>
{
this.state.persons
.map(person =>
<li key={person.id}>{person.name}</li>
)
}
</ul>
)
}
}
اول، React و Axios را Import میکنید تا هر دو در کامپوننت قابل استفاده باشند. سپس به Hook چرخه حیات componentDidMount قلاب میزنید و درخواست GETای اجرا میکنید.
از axios.get(url) با URLای از Endpoint مربوط به API استفاده میکنید تا Promiseای بگیرید که شیء پاسخی را برمیگرداند. درون شیء پاسخ، دادهای هست که سپس مقدار person به آن تخصیص مییابد.
Axios هم سبک Promise یعنی .then() و هم سینتکس مدرن async/await را پشتیبانی میکند. هرچند .then() سرراست است و در متدهای چرخه حیات خوب کار میکند، استفاده از async/await میتواند کد را در کامپوننتهای تابعی با Hookها خواناتر کند.
همچنین میتوانید اطلاعات دیگر درباره درخواست—مثل کد وضعیت زیر res.status یا اطلاعات بیشتر درون res.request—بگیرید.
کامپوننت تابعی با Hookها (Async/Await)
اپهای مدرن React کامپوننتهای تابعی و Hookها را ترجیح میدهند. مثال زیر الگوی آماده-پروداکشنی با وضعیتهای Loading و Error، لغو درخواست از طریق AbortController (پشتیبانیشده توسط Axios) و جداسازی واضح دغدغهها را نشان میدهد. این رویکرد UX را بهبود، از تنظیم وضعیت روی کامپوننتهای Unmount-شده اجتناب و با بهترین روشهای سازمانی همراستا میشود.
src/components/PersonListHooks.js
import React, { useEffect, useState } from 'react';
import axios from 'axios';
function PersonListHooks() {
const [persons, setPersons] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
const controller = new AbortController(); // Axios از AbortController پشتیبانی میکند
const fetchData = async () => {
setLoading(true);
setError(null);
try {
const res = await axios.get('https://jsonplaceholder.typicode.com/users', {
signal: controller.signal,
// headers: { Authorization: `Bearer ${token}` }, // نمونه برای احراز هویت
});
setPersons(res.data);
} catch (err) {
// تفکیک بین لغو، خطاهای شبکه و خطاهای HTTP
if (axios.isCancel?.(err) || err.name === 'CanceledError') return;
if (err.response) {
// سرور با وضعیت غیر-2xx پاسخ داد
setError(`Server error: ${err.response.status} ${err.response.statusText}`);
} else if (err.request) {
// هیچ پاسخی دریافت نشد
setError('Network error: no response from server');
} else {
// چیز دیگری حین راهاندازی درخواست رخ داد
setError(`Request error: ${err.message}`);
}
} finally {
setLoading(false);
}
};
fetchData();
return () => controller.abort(); // پاکسازی: لغو درخواست در-جریان هنگام unmount
}, []); // آرایه وابستگی خالی: یکبار هنگام mount اجرا شود
if (loading) return <p>Loading users…</p>;
if (error) return <p role="alert">{error}</p>;
return (
<ul>
{persons.map((person) => (
<li key={person.id}>{person.name}</li>
))}
</ul>
);
}
export default PersonListHooks;
چرا این الگو کار میکند (EAT و بهترین روشها):
- خوانایی async/await: پیچیدگی زنجیر کردن Promise را کم و نگهداریپذیری را برای تیمها بهبود میبخشد.
- وضعیتهای صریح: loading و error، UX قابل دسترس و منطق شفافتری برای Retryها و UIهای اسکلت فراهم میکنند.
- لغو درخواست: AbortController از شرایط Race و نشت حافظه وقتی کامپوننتی Unmount میشود یا وابستگیها تغییر میکنند جلوگیری میکند.
- تریاژ مقاوم خطا: تفکیک err.response و err.request و خطاهای دیگر به لاگهای قابل-اقدام و پیامرسانی کاربری امنتر منجر میشود.
- مقیاسپذیری: این کد در اپهای بزرگتری که بعداً Instance مربوط به Axios، Interceptorها (احراز هویت/تلهمتری) و Retry با Backoff اضافه میکنید جا میافتد.
Hookها در مقابل کامپوننتهای کلاسی — چه زمانی کدام را انتخاب کنیم:
- برای کد جدید Hookها را ترجیح دهید: مدل state/effect سادهتر، ترکیب آسانتر از طریق Hookهای سفارشی و بدون دامهای this/چرخه حیات.
- کامپوننتهای کلاسی را هنگام نگهداری کدبیسهای قدیمی یا جایی که الگوهای فقط-کلاسی وجود دارد (مثلاً Error Boundaryهای مستقر) نگه دارید تا refactor برنامهریزیشده.
- اپهای مخلوط اشکالی ندارند: Hookها را بهتدریج در کامپوننتهای برگ بپذیرید؛ سپس منطق مشترک را بهصورت Hookهای قابل استفاده مجدد بالا ببرید هنگام مدرنسازی.
این کامپوننت را به app.js خودتان اضافه کنید:
src/app.js
import PersonList from './components/PersonList.js';
function App() {
return (
<div className="App">
<PersonList/>
</div>
)
}
جایگزین (Hookها): از نسخه Hook مربوط به کامپوننت لیست استفاده کنید:
src/app.js
import PersonListHooks from './components/PersonListHooks';
function App() {
return (
<div className="App">
<PersonListHooks />
</div>
);
}
سپس اپلیکیشنتان را اجرا کنید:
npm start
اپلیکیشن را در مرورگر ببینید. فهرستی از ۱۰ نام به شما ارائه میشود.
در یک نگاه — گام ۲ (GET /users)
- هدف: رندر کردن کاربران از JSONPlaceholder.
- پیست کنید: src/components/PersonListHooks.js، Import در App.
- اجرا:
npm start.- باید ببینید: لیست نامرتب از ۱۰ نام در DOM.
خروجی مورد انتظار (بخشی از DOM):
<ul>
<li>Leanne Graham</li>
<li>Ervin Howell</li>
<li>Clementine Bauch</li>
<!-- … ۷ مورد دیگر … -->
</ul>
چکلیست پیادهسازی (درخواست POST):
[ ] فایل کامپوننت ساخته و export شد
[ ] در App import و رندر شد
[ ] بدون خطای کنسول؛ فهرست ۱۰ نام ظاهر میشود
گام ۳ — مثال درخواست POST با Axios در React
در این گام، از Axios با متد درخواست HTTP دیگری به نام POST استفاده میکنید.
زیر نسخه بهروزشدهای از کامپوننت PersonAdd است؛ که الان از async/await استفاده کرده، وضعیت HTTP را لاگ و مدیریت خطای مقاومی دارد:
src/components/PersonAdd.js
import React from 'react';
import axios from 'axios';
export default class PersonAdd extends React.Component {
state = {
name: ''
}
handleChange = event => {
this.setState({ name: event.target.value });
}
handleSubmit = async event => {
event.preventDefault();
const user = { name: this.state.name };
try {
const res = await axios.post('https://jsonplaceholder.typicode.com/users', user);
console.log('Status:', res.status);
console.log('Response data:', res.data);
} catch (err) {
if (err.response) {
console.error('POST failed with status:', err.response.status, err.response.statusText);
} else if (err.request) {
console.error('Network error: no response from server');
} else {
console.error('Request setup error:', err.message);
}
}
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
Person Name:
<input type="text" name="name" onChange={this.handleChange} />
</label>
<button type="submit">Add</button>
</form>
</div>
)
}
}
این مثال از async/await برای شفافیت استفاده کرده، res.status را برای دیدن نتیجه HTTP لاگ میکند و شامل شاخههای try/catch است که بین خطاهای سرور (err.response)، تایماوتهای شبکه (err.request) و مسائل راهاندازی درخواست (err.message) تفکیک میکنند.
درون تابع handleSubmit، اقدام پیشفرض فرم را متوقف میکنید. سپس وضعیت را به ورودی کاربر بهروزرسانی میکنید.
استفاده از POST همان شیء پاسخ با اطلاعاتی که میتوانید درون فراخوانی then استفاده کنید به شما میدهد.
برای تکمیل درخواست POST، اول ورودی کاربر را ثبت میکنید. سپس ورودی را همراه درخواست POST اضافه میکنید؛ که پاسخی به شما میدهد. سپس میتوانید پاسخ را console.log کنید؛ که باید ورودی کاربر را در فرم نشان بدهد.
این کامپوننت را به app.js خودتان اضافه کنید:
src/app.js
import PersonList from './components/PersonList';
import PersonAdd from './components/PersonAdd';
function App() {
return (
<div className="App">
<PersonAdd/>
<PersonList/>
</div>
)
}
جایگزین (Hookها): کامپوننت POST مبتنی بر Hook را جایگزین کنید:
src/app.js
import PersonAddHooks from './components/PersonAddHooks';
function App() {
return (
<div className="App">
<PersonAddHooks />
</div>
);
}
سپس اپلیکیشنتان را اجرا کنید:
npm start
اپلیکیشن را در مرورگر ببینید. فرمی برای ارسال کاربران جدید به شما ارائه میشود. بعد از ارسال کاربر جدید، کنسول را چک کنید.
در یک نگاه — گام ۳ (POST /users)
- هدف: ارسال کاربر جدید و لاگ نتیجه.
- پیست کنید: src/components/PersonAddHooks.js، Import در App.
- اجرا: نامی تایپ کنید ← Add.
- باید ببینید: وضعیت 201 یا 200 در کنسول (JSONPlaceholder ساخت را شبیهسازی میکند).
خروجی مورد انتظار برای بخشی از Console:
Status: 201
Response data: { id: 101, name: "Ada Lovelace" }
چکلیست پیادهسازی (درخواست DELETE):
[ ] ورودی، وضعیت محلی را بهروزرسانی میکند
[ ] ارسال، axios.post را trigger میکند
[ ] کنسول، وضعیت HTTP و JSON پاسخ را نشان میدهد
[ ] خطاها پیام دوستانهای نمایش میدهند (در صورت وجود)
کامپوننت تابعی POST با Hookها (Async/Await)
نسخه Hook زیر، مثال کلاسی را بازتاب اما جزئیات دوستدار-پروداکشن اضافه میکند: وضعیت Loading، پیامهای خطا، لاگ وضعیت HTTP و لغو درخواست با AbortController. این UI را واکنشگرا نگه میدارد و از بهروزرسانی وضعیت بعد از Unmount جلوگیری میکند.
src/components/PersonAddHooks.js
import React, { useState, useEffect, useRef } from 'react';
import axios from 'axios';
function PersonAddHooks() {
const [name, setName] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const lastStatus = useRef(null);
useEffect(() => {
// اینجا POST اولیهای نیست؛ controller به ازای هر ارسال ساخته میشود
return () => {
// در صورت نیاز پاکسازی
};
}, []);
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
setError(null);
const controller = new AbortController();
try {
const res = await axios.post(
'https://jsonplaceholder.typicode.com/users',
{ name },
{ signal: controller.signal }
);
lastStatus.current = res.status;
console.log('Status:', res.status);
console.log('Response data:', res.data);
setName(''); // در صورت موفقیت reset کن
} catch (err) {
if (axios.isCancel?.(err) || err.name === 'CanceledError') return;
if (err.response) {
setError(`POST failed: ${err.response.status} ${err.response.statusText}`);
} else if (err.request) {
setError('Network error: no response from server');
} else {
setError(`Request setup error: ${err.message}`);
}
} finally {
setLoading(false);
}
// اختیاری: تابعی برگردانید برای لغو اگر این را به عملیات طولانی-مدت تبدیل کنید
// return () => controller.abort();
};
return (
<form onSubmit={handleSubmit}>
<label>
Person Name:
<input
type="text"
name="name"
value={name}
onChange={(e) => setName(e.target.value)}
disabled={loading}
/>
</label>
<button type="submit" disabled={loading || !name.trim()}>
{loading ? 'Adding…' : 'Add'}
</button>
{error && <p role="alert">{error}</p>}
{lastStatus.current && <p>Last status: {lastStatus.current}</p>}
</form>
);
}
export default PersonAddHooks;
نکته: دکمه submit را حین Loading غیرفعال کنید تا از درخواستهای تکراری جلوگیری شود. برای APIهای احراز-هویتشده، فراخوانیهای POST را به Instance مشترک Axios با Interceptorهای درخواست برای Tokenها منتقل کنید.
گام ۴ — مثال درخواست DELETE با Axios در React
در این مثال میبینید چطور آیتمها را از API با axios.delete و پاس دادن URL بهعنوان پارامتر حذف کنید.
درون پروژه React خودتان، باید کامپوننت جدیدی به نام PersonRemove بسازید.
فایل PersonRemove.js را با نسخه زیر جایگزین کنید؛ که از async/await و مدیریت خطای مقاوم استفاده میکند:
src/PersonRemove.js
import React from 'react';
import axios from 'axios';
export default class PersonRemove extends React.Component {
state = {
id: ''
}
handleChange = event => {
this.setState({ id: event.target.value });
}
handleSubmit = async event => {
event.preventDefault();
const { id } = this.state;
if (!id) return;
try {
// نکته: برخی APIهای پروداکشن هدرهای احراز هویت لازم دارند؛ نکته پایین را ببینید
const res = await axios.delete(`https://jsonplaceholder.typicode.com/users/${id}` /*, {
headers: { Authorization: `Bearer <token>` }
}*/);
console.log('Status:', res.status);
console.log('Response data:', res.data);
} catch (err) {
if (err.response) {
console.error('DELETE failed with status:', err.response.status, err.response.statusText);
} else if (err.request) {
console.error('Network error: no response from server');
} else {
console.error('Request setup error:', err.message);
}
}
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
Person ID:
<input type="number" name="id" onChange={this.handleChange} />
</label>
<button type="submit">Delete</button>
</form>
</div>
)
}
}
نکته: پاسخهای API متفاوتاند. در سیستمهای پروداکشن، Endpointهای DELETE ممکن است هدرها (مثلاً Tokenهای Bearer احراز هویت یا Tokenهای CSRF) یا پارامترهای اضافی لازم داشته باشند. برای اپهای بزرگتر، Instance مشترک Axios با Interceptorهای درخواست/پاسخ (بخش Interceptorها را ببینید) را برای تزریق سازگارِ احراز هویت و تلهمتری ترجیح دهید.
کامپوننت تابعی DELETE با Hookها (Async/Await)
نسخه Hook مثال کلاسی را بازتاب و وضعیتهای Loading/Error، لاگ وضعیت و لغو درخواست اضافه میکند. این از شرایط Race جلوگیری و بازخورد UI را واکنشگرا نگه میدارد.
src/components/PersonRemoveHooks.js
import React, { useState, useRef } from 'react';
import axios from 'axios';
function PersonRemoveHooks() {
const [id, setId] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const lastStatus = useRef(null);
const handleSubmit = async (e) => {
e.preventDefault();
if (!id.trim()) return;
setLoading(true);
setError(null);
const controller = new AbortController();
try {
// برخی APIها هدرها لازم دارند (احراز هویت/CSRF). از طریق Instance Axios یا اینجا اضافه کنید.
const res = await axios.delete(
`https://jsonplaceholder.typicode.com/users/${id}`,
{ signal: controller.signal }
);
lastStatus.current = res.status;
console.log('Status:', res.status);
console.log('Response data:', res.data);
setId('');
} catch (err) {
if (axios.isCancel?.(err) || err.name === 'CanceledError') return;
if (err.response) {
setError(`DELETE failed: ${err.response.status} ${err.response.statusText}`);
} else if (err.request) {
setError('Network error: no response from server');
} else {
setError(`Request setup error: ${err.message}`);
}
} finally {
setLoading(false);
}
// اختیاری: return () => controller.abort(); // اگر به جریان طولانی-مدت تطبیقش بدهید
};
return (
<form onSubmit={handleSubmit}>
<label>
Person ID:
<input
type="number"
name="id"
value={id}
onChange={(e) => setId(e.target.value)}
disabled={loading}
/>
</label>
<button type="submit" disabled={loading || !id.trim()}>
{loading ? 'Deleting…' : 'Delete'}
</button>
{error && <p role="alert">{error}</p>}
{lastStatus.current && <p>Last status: {lastStatus.current}</p>}
</form>
);
}
export default PersonRemoveHooks;
نکته: برای APIهای احراز-هویتشده، Instance مشترک Axios با Interceptorهای درخواست را برای تزریق هدرهای Authorization و Interceptorهای پاسخ را برای مدیریت جریانهای Refresh مربوط به 401 ترجیح دهید.
src/app.js
import PersonList from './components/PersonList';
import PersonAdd from './components/PersonAdd';
import PersonRemove from './components/PersonRemove';
function App() {
return (
<div className="App">
<PersonAdd/>
<PersonList/>
<PersonRemove/>
</div>
)
}
جایگزین (Hookها): از کامپوننت delete مبتنی بر Hook استفاده کنید:
src/app.js
import PersonRemoveHooks from './components/PersonRemoveHooks';
function App() {
return (
<div className="App">
<PersonRemoveHooks />
</div>
);
}
سپس اپلیکیشنتان را اجرا کنید:
npm start
اپلیکیشن را در مرورگر ببینید. فرمی برای حذف کاربران به شما ارائه میشود.
در یک نگاه — گام ۴ (DELETE /users/:id)
- هدف: حذف کاربر با ID و تأیید نتیجه.
- پیست کنید: src/components/PersonRemoveHooks.js، Import در App.
- اجرا: ۱ را وارد کنید ← Delete.
- باید ببینید: Status: 200 و {} در کنسول (JSONPlaceholder شیء خالی برمیگرداند).
خروجی مورد انتظار (بخشی از Console):
Status: 200
Response data: {}
چکلیست پیادهسازی (Instance Axios و Interceptorها):
[ ] ورودی ثبت و اعتبارسنجی شد (غیر-خالی)
[ ] axios.delete با مسیر درست صدا زده شد
[ ] کنسول، وضعیت HTTP و بدنه پاسخ را نشان میدهد
[ ] خطاها پیام دوستانهای نمایش میدهند (در صورت وجود)
گام ۵ — ساخت Instance مربوط به Axios و استفاده از Interceptorها
Instance مشترک Axios، پیکربندی (URL پایه، هدرها، تایماوتها) را متمرکز و Interceptorها را برای احراز هویت و تلهمتری ممکن میسازد. این سازگاری را بهبود و Boilerplate را کم میکند.
ساخت Instance
// src/api.js
import axios from 'axios';
const API = axios.create({
baseURL: 'https://jsonplaceholder.typicode.com/',
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
withCredentials: false, // فقط اگر APIتان از کوکی استفاده میکند true بگذارید
});
export default API;
افزودن Interceptor درخواست (هدرهای احراز هویت، IDهای همبستگی)
// src/api.interceptors.js
import API from './api';
API.interceptors.request.use(
(config) => {
// نمونه: الصاق token احراز هویت از storage
const token = localStorage.getItem('access_token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
// نمونه: افزودن ID همبستگی برای ردیابی
config.headers['X-Request-ID'] = crypto.randomUUID?.() || Date.now().toString(36);
return config;
},
(error) => Promise.reject(error)
);
افزودن Interceptor پاسخ (مدیریت 401، تلهمتری پایه)
// src/api.interceptors.js (ادامه)
API.interceptors.response.use(
(response) => response,
async (error) => {
const { response, config } = error;
// تلهمتری پایه
console.warn('API error:', {
url: config?.url,
method: config?.method,
status: response?.status,
});
// نمونه: مدیریت token دسترسی منقضیشده
if (response?.status === 401 && !config.__isRetry) {
config.__isRetry = true;
try {
// جریان refresh شبه؛ با endpoint احراز هویت خودتان جایگزین کنید
const refreshToken = localStorage.getItem('refresh_token');
if (refreshToken) {
// await axios.post('/auth/refresh', { refreshToken });
// localStorage.setItem('access_token', newAccessToken);
// config.headers.Authorization = `Bearer ${newAccessToken}`;
return API(config); // درخواست اصلی را retry کن
}
} catch (e) {
// به reject رسیدن را ادامه بده
}
}
return Promise.reject(error);
}
);
استفاده از Instance در کامپوننتها
// src/components/PersonRemove.js
import React from 'react';
import API from '../api';
import '../api.interceptors'; // تضمین ثبت یکباره interceptorها
export default class PersonRemove extends React.Component {
state = { id: '' };
handleChange = (e) => this.setState({ id: e.target.value });
handleSubmit = async (e) => {
e.preventDefault();
try {
const res = await API.delete(`users/${this.state.id}`);
console.log(res.data);
} catch (err) {
console.error('Delete failed:', err);
}
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Person ID:
<input type="number" name="id" onChange={this.handleChange} />
</label>
<button type="submit">Delete</button>
</form>
);
}
}
نکته امنیتی: هرگز Secretها را در کد فرانتاند Hard-code نکنید. Tokenها را امن ذخیره و برای عملیاتهای حساس، Proxy مربوط به بکاند را ترجیح دهید.
گام ۶ — آیا میتوانم از Axios با async/await در React استفاده کنم؟
استفاده از async/await با Axios کد را تمیزتر و استدلال دربارهاش آسانتر میکند؛ بهویژه در اپهای مدرن React که Hookها را ترجیح میدهند. بهجای زنجیر کردن .then()، میتوانید فراخوانیها را در try/catch بپیچید تا مدیریت خطای شفافتری داشته باشید.
src/components/PersonRemove.js
import React from 'react';
import API from '../api';
export default class PersonRemove extends React.Component {
state = { id: '' };
handleChange = (e) => this.setState({ id: e.target.value });
handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await API.delete(`users/${this.state.id}`);
console.log('Status:', response.status);
console.log('Response data:', response.data);
} catch (err) {
if (err.response) {
console.error('Delete failed with status:', err.response.status, err.response.statusText);
} else if (err.request) {
console.error('Network error: no response from server');
} else {
console.error('Request setup error:', err.message);
}
}
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Person ID:
<input type="number" name="id" onChange={this.handleChange} />
</label>
<button type="submit">Delete</button>
</form>
);
}
}
چرا async/await در React؟
استفاده از async/await خوانایی را با نگهداشتن منطق از-بالا-به-پایین—بهجای تودرتوی عمیق در زنجیرههای .then()—بهبود میبخشد. این مدیریت خطا را با try/catch صریح میسازد و بهطور طبیعی با Hookها (useEffect و useState) در کامپوننتهای تابعی مدرن جفت میشود.
نحوه مدیریت خطاها با Axios در React
مدیریت خطای مؤثر، تفاوت بین اپ React مقاوم و شکننده است. این بخش توضیح میدهد چطور با Axios در React خطاها را مدیریت کنید، شیء خطای Axios چه چیزی شامل و چطور پیامهای کاربرپسند تولید کنید—در حالی که لاگهای تفصیلی را برای توسعهدهندگان نگه میدارید.
شیء خطای Axios: بررسی عمیق و بهترین روشها
هنگام کار با Axios در React، درک ساختار شیء خطا برای ساخت اپلیکیشنهای مقاوم و کاربرپسند حیاتی است. Axios شیء Error استاندارد جاوااسکریپت را با ویژگیهای اضافی تقویت میکند که زمینه تفصیلی درباره اینکه حین درخواست HTTP چه چیزی خراب شده فراهم میکنند. این به شما اجازه تفکیک بین سناریوهای شکست متفاوت—مانند خطاهای سرور، مسائل شبکه و پیکربندیهای اشتباه درخواست—و پاسخ مناسب در UI و لاگهایتان را میدهد.
کالبدشناسی خطای Axios
| فیلد | چه وقت وجود دارد | چه چیزی شامل | چطور در اپهای React استفاده شود |
|---|---|---|---|
| err.response | سرور پاسخ داد؛ اما با وضعیت غیر-2xx | شیءای: { status، statusText، data، headers، config، request } | نمایش پیامهای آگاه-از-وضعیت (مثلاً «Unauthorized» برای 401، «Not Found» برای 404، «Server Error» برای 5xx). |
| err.request | درخواست ارسال شد اما پاسخی دریافت نشد | شیء درخواست زیرین (مثلاً XMLHttpRequest در مرورگرها، http.ClientRequest در Node.js) | بهعنوان خطای شبکه رفتار کنید؛ از کاربر بخواهید اتصالش را چک کند یا Retry کند. |
| err.message | همیشه موجود | رشته قابل-خواندن-انسانی که خطا را توصیف میکند (مثلاً تایماوتها، لغوها، پیکربندیهای اشتباه) | پیام خطای عمومی نمایش، جزئیات را برای دیباگ لاگ و اگر خطا بهدلیل لغو بود تأیید کنید. |
| err.code | گاهی (مثلاً تایماوتها، خطاهای شبکه) | رشته کد خطای کوتاه (مثلاً ‘ECONNABORTED’ برای تایماوتها) | برای مدیریت خطای پیشرفته استفاده کنید؛ مثل Retry روی تایماوتها یا نمایش UI خاصی برای کدهای خطای خاص. |
| err.isAxiosError | همیشه موجود (Axios >= 0.19.0) | فلگ بولی (true اگر خطا از Axios منشأ گرفته) | تفکیک امن خطاهای Axios از سایر خطاهای پرتابشده در اپ یا Error Boundaryهای شما. |
| err.config | همیشه موجود | شیء config مربوط به Axios استفادهشده برای درخواست | برای دیباگ یا Retry کردن درخواست با پارامترهای تغییرکرده مفید. |
سناریوهای عملی مدیریت خطا
خطاهای احراز هویت/مجوز (401/403):
از err.response.status برای تشخیص اینکه کاربر احراز هویت نشده یا مجوز ندارد استفاده کنید. برای ورود درخواست کنید یا پیام دسترسی-رد-شده نشان بدهید.
منبع پیدا نشد (404):
اگر err.response.status === 404، به کاربر اطلاع بدهید منبع درخواستی وجود ندارد؛ بهجای نمایش خطای عمومی.
خطاهای سرور (5xx):
برای err.response.status >= 500، نمایش پیام «سرور موقتاً در دسترس نیست» و اختیاری اجرای منطق Retry را در نظر بگیرید.
خرابیهای شبکه:
اگر err.request وجود دارد اما err.response نه، درخواست انجام شد اما پاسخی دریافت نشد. این اغلب مشکل شبکه یا خاموش بودن سرور را نشان میدهد. به کاربر پیشنهاد اتصالش را چک کند یا بعداً دوباره امتحان کند.
تایماوتها و لغوها:
اگر err.code === 'ECONNABORTED' یا err.message شامل «timeout» است، به کاربر اطلاع بدهید درخواست طول کشید. اگر خطا بهدلیل لغو بود (مثلاً Unmount کامپوننت)، ممکن است بخواهید بیصدا نادیدهاش بگیرید.
چکهای سریع: لغو، تایماوتها و Guardهای Axios
از این چکهای کوچک و قابل اطمینان برای دستهبندی موارد خطای رایج و اجتناب از لاگهای پرنویز استفاده کنید:
import axios /*, { AxiosError }*/ from 'axios';
try {
// ...
} catch (err) {
// ۱) محدود به خطاهای Axios (در برابر exceptionهای نامرتبط Guard میکند)
if (axios.isAxiosError?.(err)) {
// ۲) لغو (کامپوننت unmount شد / کاربر ناوبری کرد)
if (err.name === 'CanceledError') {
// بیصدا نادیده بگیر یا فقط debug-log کن
return;
}
// ۳) تایماوت (Axios روی تایماوت کد ECONNABORTED میگذارد)
if (err.code === 'ECONNABORTED' || err.message?.toLowerCase().includes('timeout')) {
// اختیاری: «درخواست تایماوت شد» را نشان بده و Retry را پیشنهاد کن
}
// ۴) شبکه در مقابل وضعیت HTTP
if (err.response) {
// خطای HTTP: از err.response.status / statusText استفاده کن
} else if (err.request) {
// خطای شبکه: بدون پاسخ از سرور
}
} else {
// خطای غیر-Axios (زمان-اجرا/منطق) — دوباره پرتاب کن یا جداگانه مدیریت کن
throw err;
}
}
دامهای محیطی (مرورگرها):
- خرابیهای CORS اغلب بهصورت خطاهای شبکه ظاهر میشوند (err.request بدون err.response). هدرهای CORS سرور و مدیریت Preflight را تأیید کنید.
- Ad-Blockerها / افزونهها میتوانند درخواستها را بلاک و خطاهای شبکه را تقلید کنند. در پروفایل تمیز Repro بگیرید تا تأیید شود.
- محتوای مخلوط (HTTP←HTTPS) و پیکربندیهای اشتباه Service Worker میتوانند به خرابیهای بیصدا منجر شوند. تبهای Network و Application در DevTools را چک کنید.
مثال: شیء خطای Axios در عمل
الگوی مینیمال (Async/Await + Try/Catch):
import axios from 'axios';
try {
const res = await axios.get('/users');
// از res.data استفاده کن
} catch (err) {
if (err.response) {
console.error('Server error:', err.response.status);
} else if (err.request) {
console.error('Network error:', err.message);
} else {
console.error('Request setup error:', err.message);
}
}
الگوی پروداکشن (Hookها + Loading/Error + لغو):
import React, { useEffect, useState } from 'react';
import axios from 'axios';
export function useUsers() {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
const controller = new AbortController();
const run = async () => {
setLoading(true);
setError(null);
try {
const res = await axios.get('/users', { signal: controller.signal });
setData(res.data);
} catch (err) {
if (axios.isCancel?.(err) || err.name === 'CanceledError') return;
if (err.response) {
const { status, statusText } = err.response;
setError(`Request failed (${status} ${statusText}). Please try again.`);
} else if (err.request) {
setError('Network error: no response from server.');
} else {
setError(`Request error: ${err.message}`);
}
} finally {
setLoading(false);
}
};
run();
return () => controller.abort();
}, []);
return { data, loading, error };
}
مدیریت متمرکز با Instance Axios + Interceptorها:
از Instance مشترک برای نرمال کردن خطاها و الصاق زمینه (احراز هویت، IDهای همبستگی) استفاده کنید. این کد کامپوننت را تمیز و پیامها را سازگار نگه میدارد.
// api.js
import axios from 'axios';
const API = axios.create({ baseURL: '/api', timeout: 10000 });
export default API;
// api.errors.js — پیامها را برای UI نرمال و تشخیصها را برای لاگها نگه دار
export function normalizeAxiosError(err) {
if (err.response) {
const { status, statusText, data } = err.response;
const ui = status === 401
? 'Please log in to continue.'
: status === 403
? 'You do not have permission to perform this action.'
: status === 404
? 'The requested resource was not found.'
: status >= 500
? 'The server is unavailable right now. Please try again.'
: `Request failed (${status} ${statusText}).`;
return { ui, diag: { status, statusText, data } };
}
if (err.request) return { ui: 'Network error: no response from server.', diag: { message: err.message } };
return { ui: `Request error: ${err.message}`, diag: { message: err.message } };
}
// api.interceptors.js — زمینه اضافه کن؛ اختیاری خطاها را اینجا نگاشت کن
import API from './api';
import { normalizeAxiosError } from './api.errors';
API.interceptors.request.use((config) => {
const token = localStorage.getItem('access_token');
if (token) config.headers.Authorization = `Bearer ${token}`;
config.headers['X-Request-ID'] = crypto.randomUUID?.() || Date.now().toString(36);
return config;
});
API.interceptors.response.use(
(res) => res,
(error) => {
// پیامهای نرمالشده را برای مصرفکنندهها الصاق کن
error.normalized = normalizeAxiosError(error);
// تلهمتری پایه
console.warn('API error', {
url: error.config?.url,
method: error.config?.method,
...error.normalized.diag,
});
return Promise.reject(error);
}
);
// مصرفکننده نمونه (کامپوننت/سرویس)
import API from './api';
import './api.interceptors';
async function deleteUser(id, setError) {
try {
await API.delete(`/users/${id}`);
} catch (err) {
setError(err.normalized?.ui ?? 'Something went wrong.');
}
}
راهنماهای UX (خواننده-اول)
- متن آگاه-از-وضعیت: 401 ← «لطفاً وارد شوید»، 403 ← «بدون مجوز»، 404 ← «پیدا نشد»، 5xx ← «بهزودی دوباره امتحان کنید». از افشای جزئیات داخلی در UI بپرهیزید.
- هشدارهای قابل دسترس: از ویژگیهای role (role=”alert”) برای پیامهای خطا استفاده کنید؛ پیامها را مختصر و قابل-اقدام نگه دارید.
- Retryها: فقط برای GET/PUTهای idempotent و خطاهای گذرا/شبکه/5xx. از Backoff نمایی استفاده و تلاشها را محدود کنید.
- لغو: همیشه درخواستهای در-جریان را هنگام Unmount لغو کنید تا از بهروزرسانی وضعیت بعد از Unmount و پهنای باند هدررفته جلوگیری شود.
- قابلیت مشاهده: وضعیت، statusText، ID همبستگی و زمینه Payload مینیمال را لاگ کنید؛ از PII در لاگها بپرهیزید.
- امنیت: هرگز Tokenها یا Stack Traceها را در UI افشا نکنید؛ برای عملیاتهای حساس Proxy بکاند را ترجیح دهید.
مرجع سریع: نگاشت وضعیت ← پیام
| کلاس وضعیت | معنای معمول | پیام UI پیشنهادی |
|---|---|---|
| 4xx | خطاهای کلاینت/احراز هویت | اعتبارنامه/مجوزها را چک کنید؛ درخواستتان را بازبینی کنید. |
| 401 | احراز-نشده | لطفاً برای ادامه وارد شوید. |
| 403 | غیرمجاز/ممنوع | شما مجوز انجام این اقدام را ندارید. |
| 404 | منبع پیدا نشد | منبع درخواستی پیدا نشد. |
| 408/429 | تایماوت / محدودیت نرخ | درخواستهای زیاد یا تایماوت؛ بعداً دوباره امتحان کنید. |
| 5xx | سرور/قطعی موقت | سرور در دسترس نیست. لطفاً بهزودی دوباره امتحان کنید. |
نکات TypeScript — خطاهای Axios با تایپ قوی
- خطاها را امن محدود کنید: در
catch (err: unknown)، ازaxios.isAxiosError<ApiError>(err)برای Guard قبل از خواندن فیلدهای خاص Axios استفاده کنید. - پاسخهایتان را تایپ کنید:
axios.get<User[]>('/users')را ترجیح دهید تا res.data درست تایپ شود. - Payloadهای خطای API را مدل کنید: اینترفییس ApiError بسازید تا پیامهای سرور را بدون any افشا کنید.
import axios, { AxiosError } from 'axios';
interface User { id: number; name: string }
interface ApiError { message: string; code?: string }
async function loadUsers() {
try {
const res = await axios.get<User[]>('/users');
return res.data; // تایپشده: User[]
} catch (err: unknown) {
if (axios.isAxiosError<ApiError>(err)) {
const status = err.response?.status;
const serverMsg = err.response?.data?.message;
// پیام UI دوستانه ارائه کن؛ تشخیصها را لاگ کن
throw new Error(serverMsg ?? `Request failed${status ? ` (${status})` : ''}`);
}
// خطای غیر-Axios/زمان-اجرا — برای error boundary/تلهمتری دوباره پرتاب کن
throw err;
}
}
خلاصه: مدیریت خطای Axios را برای سازگاری متمرکز، پیامهای کاربرپسند ارائه و جزئیات تشخیصی را در لاگها نگه دارید. این بین سرعت توسعهدهنده و تجربه کاربر قابل اعتماد تعادل برقرار میکند.
بهترین روشهای استفاده از Axios در React
Axios در مقابل React Query: چه زمانی از هر کدام استفاده کنیم
در حالی که Axios درخواستهای HTTP را مستقیم مدیریت میکند، React Query (الان TanStack Query) Fetch کردن داده، کش و بهروزرسانیهای پسزمینه را برای اپهای React پیچیده انتزاع میکند.
- Axios: برای فراخوانیهای API مستقیم و یکباره، تنظیم هدرها و مدیریت منطق سطح-پایین درخواست/پاسخ عالی.
- React Query: وقتی کش، Refetch خودکار و مدیریت وضعیت Query (Loading، Error، Success) لازم دارید ایدهآل.
بهترین روش: Axios را بهعنوان Fetcher درون React Query استفاده کنید اگر هم قدرت Interceptorهای Axios و هم قدرت لایه-داده React Query را میخواهید.
مثال — استفاده از Axios با React Query
import axios from "axios";
import { useQuery } from "@tanstack/react-query";
const fetchUsers = async () => {
const { data } = await axios.get("/api/users");
return data;
};
function UserList() {
const { data, error, isLoading } = useQuery(["users"], fetchUsers);
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
این الگو بهترینِ هر دو دنیا را میدهد: قدرت درخواست Axios و کش + Reactivity مربوط به React Query.
برای ساخت اپلیکیشنهای React مقیاسپذیر، قابل نگهداری و امن، هنگام کار با Axios از این بهترین روشها پیروی کنید.
۱. از Interceptorهای Axios برای احراز هویت و تلهمتری استفاده کنید
Interceptorها به شما اجازه الصاق Tokenهای احراز هویت (مثلاً JWT یا OAuth2) و IDهای همبستگی به هر درخواست را میدهند. همچنین میتوانید پاسخها را لاگ یا خطاها را در یک مکان نرمال کنید؛ که رفتار سازگار در کل اپ را تضمین میکند.
۲. Hookهای سفارشی بسازید (مثلاً useAxios) برای قابلیت استفاده مجدد
منطق Axios را در Hookهای سفارشی کپسوله کنید تا کامپوننتهایتان ساده شوند. Hookِ useAxios میتواند وضعیتهای Loading، Error و Retry را مدیریت و همزمان داده برگرداند. این کامپوننتهای تمیزتر را ترویج و به شما اجازه استفاده مجدد منطق درخواست در سراسر پروژه را میدهد.
۳. منطق API را از کامپوننتها جدا کنید
کامپوننتهای React خودتان را روی UI متمرکز نگه دارید. فراخوانیهای Axios را در ماژولهای API اختصاصی (مثلاً api.js) یا Hookها قرار بدهید؛ سپس آنها را در کامپوننتهایتان Import کنید. این جداسازی قابلیت تست را بهبود و جایگزینی پیادهسازیهای API را آسانتر میسازد.
۴. Axios در مقابل Fetch — مرجع سریع و مقایسه عمیق
هنگام انتخاب بین Axios و API بومی Fetch برای ساخت درخواستهای HTTP در React (یا هر پروژه جاوااسکریپت دیگری)، مهم است پیچیدگی اپلیکیشن، نیازهای نگهداری و تجربه توسعهدهنده را در نظر بگیرید.
Axios کتابخانه شخص ثالث محبوبی است که درخواستهای HTTP را با سینتکس مختصر، پارس خودکار JSON و قابلیتهای قدرتمندی مثل Interceptorها، لغو درخواست و مدیریت خطای مقاوم ساده میکند. Fetch API مدرن و داخلی مرورگر است که رابط سطح-پایینی برای ساخت درخواستهای HTTP فراهم میکند؛ اما برای وظایف رایج کار دستی بیشتری لازم دارد.
چه زمانی از Axios استفاده کنیم:
- اپلیکیشنهای بزرگتر یا در-سطح-سازمانی که نیاز دارید:
- مدیریت خطای سازگار در کل اپ
- پارس و تبدیل خودکار JSON
- Interceptorهای درخواست/پاسخ برای احراز هویت، لاگینگ یا تلهمتری
- پشتیبانی داخلی از لغو درخواست (با AbortController)
- سینتکس سادهتر برای موارد استفاده رایج (مثلاً POST کردن JSON، مدیریت تایماوتها)
- پشتیبانی از مرورگرهای قدیمیتر (با Polyfillها)
چه زمانی از Fetch استفاده کنیم:
- پروژههای کوچکتر، Prototypeهای سریع یا وقتی حجم Bundle حیاتی است
- وقتی میخواهید از وابستگیهای خارجی اجتناب کنید
- اگر فقط درخواستهای GET/POST پایه لازم دارید و با مدیریت دستی JSON و خطاها راحت هستید
۵. جدول مقایسه ویژگی-به-ویژگی
| ویژگی | Axios | API مربوط به Fetch |
|---|---|---|
| سینتکس | تمیزتر، مبتنی بر Promise با Boilerplate کمتر | پرحرفتر، پارس دستی JSON لازم دارد |
| مدیریت خطا | پرتاب خودکار روی پاسخهای غیر-2xx | باید response.ok را دستی چک کنید |
| Interceptorها | Interceptorهای درخواست/پاسخ داخلی | موجود نیست، Wrapperهای سفارشی لازم دارد |
| مدیریت JSON | JSON را خودکار پارس میکند | res.json() صریح لازم دارد |
| لغو درخواست | پشتیبانی داخلی (AbortController و Cancel Tokenها) | فقط AbortController، یکپارچهسازی دستی |
| پشتیبانی تایماوت | پشتیبانی نیتیو از طریق config | پیادهسازی دستی لازم دارد |
| رویدادهای پیشرفت | پشتیبانیشده (مرورگر، Node) | بهصورت نیتیو پشتیبانی نمیشود |
| آپلود/دانلود | با Axios آسانتر | با Fetch دستیتر |
| پشتیبانی مرورگر | در همه مرورگرهای اصلی کار میکند (با Polyfill) | فقط مرورگرهای مدرن |
نکته: برای اپهای در-سطح-سازمانی، Axios با Interceptorها و مدیریت خطا زمانِ توسعه را ذخیره میکند. برای اپهای کوچک یا وقتی حجم Bundle مهم است، Fetch ممکن است کافی باشد.
۶. Hook سفارشی قابل استفاده مجدد: useAxios (با Instance مربوط به API)
میتوانید منطق Axios را در Hook سفارشی کپسوله کنید:
// src/hooks/useAxios.js
import { useEffect, useState } from 'react';
import API from '../api';
export function useAxios(url, options = {}) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const controller = new AbortController();
const fetchData = async () => {
setLoading(true);
setError(null);
try {
const res = await API.get(url, { ...options, signal: controller.signal });
setData(res.data);
} catch (err) {
if (axios.isCancel?.(err)) return;
setError(err);
} finally {
setLoading(false);
}
};
fetchData();
return () => controller.abort();
}, [url]);
return { data, loading, error };
}
مثالهای یکپارچهسازی اپ
یکپارچهسازی کامپوننتهای API در اپلیکیشن اصلی برای ساخت اپ React عملی و تعاملی ضروری است. در پایین میبینید چطور کامپوننتهای PersonList، PersonAdd و PersonRemove را در App.js برای هر دو پیادهسازی مبتنی بر کلاس و مبتنی بر Hook ترکیب کنید.
یکپارچهسازی کامپوننتهای کلاسی: PersonList، PersonAdd و PersonRemove
در این مثال، هر سه کامپوننت مبتنی بر کلاس را Import و در App.js خودتان رندر میکنید. این راهاندازی به کاربران اجازه افزودن شخص، دیدن فهرست و حذف شخص را—همه در یک مکان—میدهد. این الگو در داشبوردها و پنلهای مدیریتی رایج است:
// src/App.js
import PersonList from './components/PersonList';
import PersonAdd from './components/PersonAdd';
import PersonRemove from './components/PersonRemove';
function App() {
return (
<div className="App">
<h2>Add a Person</h2>
<PersonAdd />
<h2>People List</h2>
<PersonList />
<h2>Remove a Person</h2>
<PersonRemove />
</div>
);
}
export default App;
چرا این یکپارچهسازی؟
ترکیب عملیات ساخت، خواندن و حذف در نمای منفرد اپ، به کاربران اجازه تعامل با API به شیوهای منسجم را میدهد. همچنین مدیریت وضعیت و دیدن اثرات هر اقدام در بافت را آسانتر میسازد.
یکپارچهسازی کامپوننتهای تابعی با Hookها: PersonListHooks، PersonAddHooks و PersonRemoveHooks
برای اپهای مدرن، نسخههای مبتنی بر Hook را با هم ترکیب کنید:
// src/App.js
import PersonListHooks from './components/PersonListHooks';
import PersonAddHooks from './components/PersonAddHooks';
import PersonRemoveHooks from './components/PersonRemoveHooks';
function App() {
return (
<div className="App">
<h2>Add a Person</h2>
<PersonAddHooks />
<h2>People List</h2>
<PersonListHooks />
<h2>Remove a Person</h2>
<PersonRemoveHooks />
</div>
);
}
export default App;
نتیجهگیری
در این آموزش، نحوه استفاده از Axios با React را یاد گرفتید—از درخواستهای GET و POST و DELETE گرفته تا ساخت Instance مشترک با Interceptorها، مدیریت خطای مقاوم و الگوهای پیشرفته مثل React Query. با این قابلیتها میتوانید اپلیکیشنهای React مقیاسپذیر، قابل نگهداری و امن بسازید که مدیریت داده در آنها تمیز و کارآمد است.




