كيفية تنفيذ عمليات CRUD باستخدام React وReact Hooks وAxios
مقدمة: لماذا تحتاج إلى فهم عمليات CRUD في React؟
عند تطوير واجهات تفاعلية حديثة، لا يكفي عرض البيانات فقط، بل يجب أيضاً إنشاء السجلات وقراءتها وتحديثها وحذفها بطريقة مرنة وآمنة. وهنا تظهر أهمية عمليات CRUD، وهي اختصار للعمليات الأساسية الأربع: Create وRead وUpdate وDelete.
في هذا الدليل العملي، سنتعلم كيفية بناء تطبيق متكامل باستخدام React وReact Hooks وAxios وReact Router، مع الاستفادة من Semantic UI React لتنسيق الواجهة. الهدف ليس فقط نسخ كود يعمل، بل فهم آلية الربط بين الواجهة البرمجية API وحالة التطبيق بطريقة واضحة وقابلة للتطوير.

تثبيت Node.js وnpm
قبل البدء، تحتاج إلى تثبيت Node.js لأنه البيئة الأساسية التي سنستخدمها لتشغيل أدوات تطوير JavaScript. كما ستحتاج إلى npm، وهو مدير الحزم المدمج مع Node.js لتثبيت المكتبات المطلوبة داخل المشروع.
- انتقل إلى الموقع الرسمي:
https://nodejs.org/en/ - نزّل النسخة المناسبة لنظامك وثبّتها.
- بعد اكتمال التثبيت، افتح الطرفية
Terminalأو موجه الأوامر واكتب:
node -v
سيعرض هذا الأمر إصدار Node.js المثبّت لديك، وهو مؤشر سريع للتأكد من نجاح التثبيت.
إنشاء مشروع React جديد
لإنشاء تطبيق جديد باستخدام أداة create-react-app، نفّذ الأمر التالي:
npx create-react-app react-crud
بعد تثبيت الحزم، انتقل إلى مجلد المشروع ثم شغّل التطبيق:
cd react-crud
npm start
عندها سيعمل القالب الافتراضي لـReact على المتصفح.


تثبيت مكتبة Semantic UI React
لتصميم الواجهة بشكل سريع واحترافي، سنستخدم مكتبة Semantic UI React التي توفر مكونات جاهزة مثل الأزرار والنماذج والجداول.
يمكنك تثبيتها باستخدام أحد الأوامر التالية:
yarn add semantic-ui-react semantic-ui-css
npm install semantic-ui-react semantic-ui-css
بعد ذلك، استورد ملف التنسيق في الملف الرئيسي index.js:
import 'semantic-ui-css/semantic.min.css';
تهيئة الواجهة الرئيسية للتطبيق
ابدأ بتعديل ملف App.js لإضافة عنوان رئيسي للتطبيق:
import './App.css';
function App() {
return (
<div>React Crud Operations</div>
);
}
export default App;
ثم اجعل العنوان في المنتصف بإضافة className مناسب:
import './App.css';
function App() {
return (
<div className="main">React Crud Operations</div>
);
}
export default App;
وفي ملف App.css:
.main {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}

لتحسين شكل العنوان، استخدم وسم <h2> وأضف خطاً مميزاً من Google Fonts مثل Montserrat:
import './App.css';
function App() {
return (
<div className="main">
<h2 className="main-header">React Crud Operations</h2>
</div>
);
}
export default App;
@import url('https://fonts.googleapis.com/css2?family=Montserrat&display=swap');
.main-header {
font-family: 'Montserrat', sans-serif;
}

إنشاء مكونات عمليات CRUD
داخل مجلد src، أنشئ مجلداً باسم components، ثم أضف الملفات التالية:
create.jsread.jsupdate.js
لن نحتاج إلى ملف مستقل لعملية الحذف، لأننا سننفذها مباشرة من واجهة القراءة.

إعداد MockAPI لاختبار الطلبات
لأننا نحتاج إلى واجهة برمجية تجريبية، سنستخدم خدمة MockAPI لإنشاء خادم وهمي نستطيع إرسال الطلبات إليه واسترجاع البيانات منه.
- انتقل إلى
https://mockapi.io/ - أنشئ حساباً جديداً.
- أنشئ مشروعاً جديداً.
- أضف مورداً جديداً
ResourceمثلfakeData. - احذف الحقول غير الضرورية مثل
avatarوcreatedAt.







بعد إنشاء المورد، ستحصل على رابط API endpoint سنستخدمه في عمليات الإضافة والقراءة والتعديل والحذف.
بناء نموذج الإضافة Create
إضافة نموذج من Semantic UI React
يمكنك استخدام مكوّن Form الجاهز داخل ملف Create.js:
import React from 'react';
import { Button, Checkbox, Form } from 'semantic-ui-react';
const Create = () => (
<Form>
<Form.Field>
<label>First Name</label>
<input placeholder='First Name' />
</Form.Field>
<Form.Field>
<label>Last Name</label>
<input placeholder='Last Name' />
</Form.Field>
<Form.Field>
<Checkbox label='I agree to the Terms and Conditions' />
</Form.Field>
<Button type='submit'>Submit</Button>
</Form>
);
export default Create;
ثم استورد هذا المكوّن داخل App.js:
import './App.css';
import Create from './components/create';
function App() {
return (
<div className="main">
<h2 className="main-header">React Crud Operations</h2>
<div>
<Create />
</div>
</div>
);
}
export default App;

تحسين تنسيق النموذج
لجعل النموذج أكثر وضوحاً، أضف className إلى النموذج:
import React from 'react';
import { Button, Checkbox, Form } from 'semantic-ui-react';
const Create = () => (
<Form className="create-form">
<Form.Field>
<label>First Name</label>
<input placeholder='First Name' />
</Form.Field>
<Form.Field>
<label>Last Name</label>
<input placeholder='Last Name' />
</Form.Field>
<Form.Field>
<Checkbox label='I agree to the Terms and Conditions' />
</Form.Field>
<Button type='submit'>Submit</Button>
</Form>
);
export default Create;
وفي App.css:
.create-form label {
color: whitesmoke !important;
font-family: 'Montserrat', sans-serif;
font-size: 12px !important;
}
.main {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #212121;
color: whitesmoke;
flex-direction: column;
}

إدارة الحقول باستخدام useState
للتعامل مع القيم المدخلة داخل النموذج، نستخدم useState لإنشاء حالات مستقلة لكل حقل:
import React, { useState } from 'react';
import { Button, Checkbox, Form } from 'semantic-ui-react';
export default function Create() {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [checkbox, setCheckbox] = useState(false);
return (
<div>
<Form className="create-form">
<Form.Field>
<label>First Name</label>
<input placeholder='First Name' />
</Form.Field>
<Form.Field>
<label>Last Name</label>
<input placeholder='Last Name' />
</Form.Field>
<Form.Field>
<Checkbox label='I agree to the Terms and Conditions' />
</Form.Field>
<Button type='submit'>Submit</Button>
</Form>
</div>
);
}
بعد ذلك اربط الحقول بحالاتها:
<input placeholder='First Name' onChange={(e) => setFirstName(e.target.value)} />
<input placeholder='Last Name' onChange={(e) => setLastName(e.target.value)} />
<Checkbox label='I agree to the Terms and Conditions' onChange={() => setCheckbox(!checkbox)} />
اختبار البيانات محلياً قبل الإرسال
من الجيد اختبار القيم في وحدة التحكم قبل ربطها بالخادم. أنشئ دالة باسم postData:
const postData = () => {
console.log(firstName);
console.log(lastName);
console.log(checkbox);
};
ثم اربطها بزر الإرسال:
<Button onClick={postData} type='submit'>Submit</Button>
import React, { useState } from 'react';
import { Button, Checkbox, Form } from 'semantic-ui-react';
export default function Create() {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [checkbox, setCheckbox] = useState(false);
const postData = () => {
console.log(firstName);
console.log(lastName);
console.log(checkbox);
};
return (
<div>
<Form className="create-form">
<Form.Field>
<label>First Name</label>
<input placeholder='First Name' onChange={(e) => setFirstName(e.target.value)} />
</Form.Field>
<Form.Field>
<label>Last Name</label>
<input placeholder='Last Name' onChange={(e) => setLastName(e.target.value)} />
</Form.Field>
<Form.Field>
<Checkbox label='I agree to the Terms and Conditions' onChange={() => setCheckbox(!checkbox)} />
</Form.Field>
<Button onClick={postData} type='submit'>Submit</Button>
</Form>
</div>
);
}

إرسال الطلبات باستخدام Axios
الآن ننتقل من مرحلة التجربة المحلية إلى مرحلة الاتصال الفعلي بالواجهة البرمجية.
ثبّت مكتبة Axios:
npm i axios

استورد المكتبة في أعلى الملف:
import axios from 'axios';
ثم عدّل دالة postData لإرسال طلب POST:
const postData = () => {
axios.post('https://60fbca4591156a0017b4c8a7.mockapi.io/fakeData', {
firstName,
lastName,
checkbox
});
};
عند الضغط على زر الإرسال، سيتم إرسال البيانات إلى المورد التجريبي في MockAPI.


إضافة التوجيه بين الصفحات باستخدام React Router
للتنقل بين صفحات الإنشاء والقراءة والتحديث، نحتاج إلى مكتبة react-router-dom.
npm i react-router-dom
استورد الأدوات الأساسية:
import { BrowserRouter as Router, Route } from 'react-router-dom';
ثم لف التطبيق كله داخل Router:
import './App.css';
import Create from './components/create';
import { BrowserRouter as Router, Route } from 'react-router-dom';
function App() {
return (
<Router>
<div className="main">
<h2 className="main-header">React Crud Operations</h2>
<div>
<Route exact path='/create' component={Create} />
</div>
</div>
</Router>
);
}
export default App;
بعد ذلك أضف مسارات القراءة والتحديث:
import './App.css';
import Create from './components/create';
import Read from './components/read';
import Update from './components/update';
import { BrowserRouter as Router, Route } from 'react-router-dom';
function App() {
return (
<Router>
<div className="main">
<h2 className="main-header">React Crud Operations</h2>
<div>
<Route exact path='/create' component={Create} />
</div>
<div style={{ marginTop: 20 }}>
<Route exact path='/read' component={Read} />
</div>
<Route path='/update' component={Update} />
</div>
</Router>
);
}
export default App;


تنفيذ عملية القراءة Read
إنشاء جدول عرض البيانات
استخدم مكوّن Table من مكتبة Semantic UI React:
import React from 'react';
import { Table } from 'semantic-ui-react';
export default function Read() {
return (
<div>
<Table singleLine>
<Table.Header>
<Table.Row>
<Table.HeaderCell>First Name</Table.HeaderCell>
<Table.HeaderCell>Last Name</Table.HeaderCell>
<Table.HeaderCell>Checked</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
<Table.Row>
<Table.Cell>Nishant</Table.Cell>
<Table.Cell>Kumar</Table.Cell>
<Table.Cell>Yes</Table.Cell>
</Table.Row>
</Table.Body>
</Table>
</div>
);
}


جلب البيانات باستخدام useEffect وaxios.get
بما أننا نريد تحميل البيانات عند فتح الصفحة، سنستخدم useEffect مع حالة مصفوفة لتخزين النتائج:
import React, { useEffect, useState } from 'react';
import axios from 'axios';
const [APIData, setAPIData] = useState([]);
useEffect(() => {
axios.get('https://60fbca4591156a0017b4c8a7.mockapi.io/fakeData')
.then((response) => {
setAPIData(response.data);
});
}, []);
ثم اعرض النتائج باستخدام map():
<Table.Body>
{APIData.map((data) => {
return (
<Table.Row key={data.id}>
<Table.Cell>{data.firstName}</Table.Cell>
<Table.Cell>{data.lastName}</Table.Cell>
<Table.Cell>{data.checkbox ? 'Checked' : 'Unchecked'}</Table.Cell>
</Table.Row>
);
})}
</Table.Body>
استخدام العامل الشرطي الثلاثي هنا مفيد لعرض قيمة منطقية Boolean بشكل مفهوم للمستخدم.

تنفيذ عملية التحديث Update
إضافة زر التحديث داخل الجدول
أضف عموداً جديداً للتحديث:
<Table.HeaderCell>Update</Table.HeaderCell>
<Table.Cell>
<Button>Update</Button>
</Table.Cell>
وللانتقال إلى صفحة التحديث، استخدم Link من react-router-dom:
import { Link } from 'react-router-dom';
<Link to='/update'>
<Table.Cell>
<Button>Update</Button>
</Table.Cell>
</Link>
تخزين بيانات السجل في localStorage
حتى نعرف أي سجل سنقوم بتعديله، نحتاج إلى تخزين بياناته مؤقتاً داخل المتصفح:
<Button onClick={() => setData(data)}>Update</Button>
const setData = (data) => {
let { id, firstName, lastName, checkbox } = data;
localStorage.setItem('ID', id);
localStorage.setItem('First Name', firstName);
localStorage.setItem('Last Name', lastName);
localStorage.setItem('Checkbox Value', checkbox);
};

إعادة استخدام نموذج الإنشاء في صفحة التحديث
يمكنك إعادة استخدام نفس بنية النموذج في ملف update.js مع بعض التعديلات:
import React, { useState } from 'react';
import { Button, Checkbox, Form } from 'semantic-ui-react';
import axios from 'axios';
export default function Update() {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [checkbox, setCheckbox] = useState(false);
return (
<div>
<Form className="create-form">
<Form.Field>
<label>First Name</label>
<input placeholder='First Name' onChange={(e) => setFirstName(e.target.value)} />
</Form.Field>
<Form.Field>
<label>Last Name</label>
<input placeholder='Last Name' onChange={(e) => setLastName(e.target.value)} />
</Form.Field>
<Form.Field>
<Checkbox label='I agree to the Terms and Conditions' onChange={() => setCheckbox(!checkbox)} />
</Form.Field>
<Button type='submit'>Update</Button>
</Form>
</div>
);
}
ثم استخدم useEffect لتحميل القيم المخزنة من localStorage عند فتح الصفحة:
const [id, setID] = useState(null);
useEffect(() => {
setID(localStorage.getItem('ID'));
setFirstName(localStorage.getItem('First Name'));
setLastName(localStorage.getItem('Last Name'));
setCheckbox(localStorage.getItem('Checkbox Value'));
}, []);
واجعل الحقول معبأة تلقائياً:
<Form className="create-form">
<Form.Field>
<label>First Name</label>
<input placeholder='First Name' value={firstName} onChange={(e) => setFirstName(e.target.value)} />
</Form.Field>
<Form.Field>
<label>Last Name</label>
<input placeholder='Last Name' value={lastName} onChange={(e) => setLastName(e.target.value)} />
</Form.Field>
<Form.Field>
<Checkbox label='I agree to the Terms and Conditions' checked={checkbox} onChange={() => setCheckbox(!checkbox)} />
</Form.Field>
<Button type='submit'>Update</Button>
</Form>

إرسال طلب التحديث PUT
أنشئ دالة باسم updateAPIData:
const updateAPIData = () => {
axios.put(`https://60fbca4591156a0017b4c8a7.mockapi.io/fakeData/${id}`, {
firstName,
lastName,
checkbox
});
};
ثم اربطها بزر التحديث:
<Button type='submit' onClick={updateAPIData}>Update</Button>
الآن يمكنك تعديل أي حقل ثم إرسال التحديث ليُحفظ مباشرة في API.



تنفيذ عملية الحذف Delete
أضف زر حذف داخل الجدول:
<Table.Cell>
<Button onClick={() => onDelete(data.id)}>Delete</Button>
</Table.Cell>
ثم أنشئ دالة الحذف:
const onDelete = (id) => {
axios.delete(`https://60fbca4591156a0017b4c8a7.mockapi.io/fakeData/${id}`);
};
لكن من الأفضل تحديث الجدول مباشرة بعد الحذف، لذلك أنشئ دالة لجلب البيانات:
const getData = () => {
axios.get('https://60fbca4591156a0017b4c8a7.mockapi.io/fakeData')
.then((getData) => {
setAPIData(getData.data);
});
};
ثم استدعها بعد نجاح الحذف:
const onDelete = (id) => {
axios.delete(`https://60fbca4591156a0017b4c8a7.mockapi.io/fakeData/${id}`)
.then(() => {
getData();
});
};


تحسين تجربة المستخدم بعد الإنشاء والتحديث
من الأفضل نقل المستخدم تلقائياً إلى صفحة القراءة بعد إنشاء سجل جديد أو تحديث سجل موجود. لتحقيق ذلك، استخدم useHistory.
في صفحة الإنشاء:
import { useHistory } from 'react-router';
let history = useHistory();
const postData = () => {
axios.post('https://60fbca4591156a0017b4c8a7.mockapi.io/fakeData', {
firstName,
lastName,
checkbox
}).then(() => {
history.push('/read');
});
};
وفي صفحة التحديث:
import React, { useState, useEffect } from 'react';
import { Button, Checkbox, Form } from 'semantic-ui-react';
import axios from 'axios';
import { useHistory } from 'react-router';
export default function Update() {
let history = useHistory();
const [id, setID] = useState(null);
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [checkbox, setCheckbox] = useState(false);
useEffect(() => {
setID(localStorage.getItem('ID'));
setFirstName(localStorage.getItem('First Name'));
setLastName(localStorage.getItem('Last Name'));
setCheckbox(localStorage.getItem('Checkbox Value'));
}, []);
const updateAPIData = () => {
axios.put(`https://60fbca4591156a0017b4c8a7.mockapi.io/fakeData/${id}`, {
firstName,
lastName,
checkbox
}).then(() => {
history.push('/read');
});
};
return (
<div>
<Form className="create-form">
<Form.Field>
<label>First Name</label>
<input placeholder='First Name' value={firstName} onChange={(e) => setFirstName(e.target.value)} />
</Form.Field>
<Form.Field>
<label>Last Name</label>
<input placeholder='Last Name' value={lastName} onChange={(e) => setLastName(e.target.value)} />
</Form.Field>
<Form.Field>
<Checkbox label='I agree to the Terms and Conditions' checked={checkbox} onChange={() => setCheckbox(!checkbox)} />
</Form.Field>
<Button type='submit' onClick={updateAPIData}>Update</Button>
</Form>
</div>
);
}
هذه الخطوة البسيطة تمنح التطبيق تدفقاً أكثر احترافية وتقلل الحاجة إلى التنقل اليدوي.
أفضل ممارسات مهمة عند بناء تطبيق CRUD في React
- احرص على فصل المكونات حسب المسؤولية لتسهيل الصيانة.
- تأكد من استخدام
keyفريد عند استخدامmap()داخل الجداول والقوائم. - أضف معالجة أخطاء باستخدام
catch()عند التعامل معAxios. - يفضل لاحقاً استخدام إدارة حالة مركزية إذا كبر المشروع، مثل
Context APIأوRedux. - حاول استبدال
localStorageمستقبلاً بتمرير الحالة عبر التوجيه أو استخدام حلول أكثر مرونة في التطبيقات الكبيرة.
الخلاصة التقنية
يوضح هذا التطبيق كيف يمكن الجمع بين React وReact Hooks وAxios وReact Router لبناء دورة بيانات كاملة تبدأ من إدخال السجل وتنتهي بحذفه أو تعديله. تقنياً، الفكرة الأساسية ليست في الأكواد نفسها فقط، بل في فهم العلاقة بين الحالة State والطلبات الشبكية HTTP Requests وتحديث الواجهة بعد كل عملية. وإذا أتقنت هذا النمط، فستكون قادراً على بناء لوحات تحكم ونماذج أعمال أكثر تعقيداً بكفاءة أكبر.