كيفية تمرير البيانات والأحداث بين المكوّنات في React باحترافية

دقائق القراءة: 6

مقدمة: لماذا نحتاج إلى تمرير البيانات بين المكوّنات في React؟

عند بناء تطبيقات تفاعلية باستخدام React، ستجد سريعاً أن المكوّنات لا تعمل بمعزل عن بعضها. فقد تحتاج إلى إرسال بيانات من مكوّن أب إلى مكوّن ابن، أو إعادة بيانات من المكوّن الابن إلى المكوّن الأب بعد تنفيذ إجراء معيّن مثل النقر على زر، فتح نافذة منبثقة، أو تحديث سجل ضمن عمليات CRUD المرتبطة بواجهات API.

تكمن أهمية هذه الفكرة في أنها تساعدك على تنظيم منطق التطبيق بصورة واضحة، وتضمن تدفق البيانات بشكل قابل للصيانة والتوسّع. في هذا الدليل العملي، ستتعرّف على أشهر الطرق لتمرير البيانات والأحداث بين المكوّنات في React باستخدام props وuseState، مع أمثلة سهلة ومباشرة.

شرح تمرير البيانات بين مكوّنات React باستخدام props وuseState

تمرير البيانات من المكوّن الأب إلى المكوّن الابن

هذا هو السيناريو الأكثر شيوعاً في React. الفكرة الأساسية هي أن المكوّن الأب يحتفظ بالبيانات، ثم يمررها إلى المكوّن الابن عبر props.

إنشاء مكوّنين: الأب والابن

لنبدأ بإنشاء مكوّنين بسيطين:

import React from 'react'
export default function Parent() {
  return (
    <div></div>
  )
}
import React from 'react'
export default function Child() {
  return (
    <div></div>
  )
}

استدعاء المكوّن الابن داخل المكوّن الأب

بعد ذلك، قم باستيراد المكوّن Child داخل المكوّن Parent:

import React from 'react'
import Child from './Child';

export default function Parent() {
  return (
    <div>
      <Child />
    </div>
  )
}

استخدام useState لتخزين البيانات وإرسالها

الآن سننشئ حالة state داخل المكوّن الأب، ثم نربطها بزر يقوم بتحديث هذه البيانات عند النقر:

import React from 'react'
import Child from './Child';
import { Button } from 'semantic-ui-react';
import { useState } from 'react';
import './App.css';

export default function Parent() {
  const [data, setData] = useState('');

  const parentToChild = () => {
    setData("This is data from Parent Component to the Child Component.");
  }

  return (
    <div className="App">
      <Child />
      <div>
        <Button primary onClick={() => parentToChild()}>
          Click Parent
        </Button>
      </div>
    </div>
  )
}

في هذا المثال، عند الضغط على الزر Click Parent يتم تشغيل الدالة parentToChild()، والتي تقوم بتخزين نص داخل المتغير data.

تمرير البيانات إلى المكوّن الابن عبر props

لإرسال هذه البيانات إلى المكوّن الابن، مرّرها كخاصية عند استدعاء Child:

<Child parentToChild={data} />

هنا:

  • data: هي القيمة الفعلية التي نريد تمريرها.
  • parentToChild: هو اسم الخاصية prop التي سيستقبلها المكوّن الابن.

استقبال البيانات داخل المكوّن الابن

يمكن استقبال البيانات بطريقتين، حسب نوع المكوّن المستخدم.

الحالة الأولى: مكوّن وظيفي Functional Component

import React from 'react'

export default function Child({ parentToChild }) {
  return (
    <div>{parentToChild}</div>
  )
}

الحالة الثانية: مكوّن صنفي Class Component

import React, { Component } from 'react'

export default class Child extends Component {
  render() {
    return (
      <div>{this.props.parentToChild}</div>
    )
  }
}

في كلتا الحالتين، سيتم عرض البيانات القادمة من المكوّن الأب بالشكل نفسه.

عرض البيانات المرسلة من المكوّن الأب إلى المكوّن الابن في React

وعند النقر على الزر Click Parent، ستظهر الرسالة على الشاشة.

الكود الكامل للمكوّن الأب

import React from 'react'
import Child from './Child';
import { Button } from 'semantic-ui-react';
import { useState } from 'react';
import './App.css';

export default function Parent() {
  const [data, setData] = useState('');

  const parentToChild = () => {
    setData("This is data from Parent Component to the Child Component.");
  }

  return (
    <div className="App">
      <Child parentToChild={data} />
      <div className="child">
        <Button primary onClick={() => parentToChild()}>
          Click Parent
        </Button>
      </div>
    </div>
  )
}

تمرير البيانات من المكوّن الابن إلى المكوّن الأب

هذا السيناريو يبدو أكثر تعقيداً في البداية، لأن تدفق البيانات في React يكون عادة من الأعلى إلى الأسفل. لكن يمكن تنفيذ ذلك بسهولة عبر تمرير دالة من الأب إلى الابن، ثم استدعاؤها من داخل الابن مع إرسال البيانات المطلوبة.

إنشاء دالة في المكوّن الأب لاستقبال بيانات الابن

ابدأ بإنشاء حالة فارغة باسم data، ثم أنشئ دالة باسم childToParent:

const [data, setData] = useState('');

const childToParent = () => {
}

تمرير الدالة إلى المكوّن الابن

الخطوة التالية هي إرسال الدالة نفسها إلى المكوّن الابن باستخدام props:

<Child childToParent={childToParent} />

استدعاء الدالة من داخل الابن مع تمرير البيانات

داخل المكوّن الابن، نستقبل الدالة كخاصية، ثم نربطها بزر onClick. كما نجهّز قيمة نريد إرسالها إلى المكوّن الأب:

import React from 'react'
import { Button } from 'semantic-ui-react';

export default function Child({ childToParent }) {
  const data = "This is data from Child Component to the Parent Component.";

  return (
    <div>
      <Button primary onClick={() => childToParent(data)}>
        Click Child
      </Button>
    </div>
  )
}

بمجرد النقر على الزر، سيقوم المكوّن الابن بإرسال القيمة المخزنة في data إلى الدالة القادمة من المكوّن الأب.

استقبال القيمة في المكوّن الأب وتحديث الحالة

import './App.css';
import { useState } from 'react';
import Child from './Child';

function Parent() {
  const [data, setData] = useState('');

  const childToParent = (childdata) => {
    setData(childdata);
  }

  return (
    <div className="App">
      <div>
        <Child />
      </div>
    </div>
  );
}

export default Parent;

ولعرض البيانات القادمة من المكوّن الابن، أظهر المتغير data داخل واجهة المكوّن الأب:

import './App.css';
import { useState } from 'react';
import Child from './Child';

function Parent() {
  const [data, setData] = useState('');

  const childToParent = (childdata) => {
    setData(childdata);
  }

  return (
    <div className="App">
      {data}
      <div>
        <Child childToParent={childToParent} />
      </div>
    </div>
  );
}

export default Parent;

الآن، عندما تضغط على الزر Click Child، ستنتقل البيانات من الابن إلى الأب وتظهر على الشاشة.

تمرير البيانات من المكوّن الابن إلى المكوّن الأب في React

تمرير الأحداث بين المكوّنات في React

لا يقتصر الأمر على البيانات فقط، بل يمكنك أيضاً تمرير أحداث مثل onClick أو onChange باستخدام الأسلوب نفسه. الفكرة هنا أن المكوّن الأب يعرّف دالة، ثم يمررها إلى المكوّن الابن، ليقوم الابن باستدعائها عند وقوع الحدث.

مثال: تشغيل alert() في الأب عبر زر داخل الابن

في المكوّن الأب:

import './App.css';
import Child from './Child';

function Parent() {
  const childToParent = () => {
    alert("This is an alert from the Child Component")
  }

  return (
    <div className="App">
      <div className="child">
        <Child childToParent={childToParent} />
      </div>
    </div>
  );
}

export default Parent;

وفي المكوّن الابن:

import React from 'react'
import { Button } from 'semantic-ui-react';

export default function Child({ childToParent }) {
  return (
    <div>
      <Button primary onClick={() => childToParent()}>
        Click Child
      </Button>
    </div>
  )
}

عند النقر على الزر داخل المكوّن الابن، سيتم استدعاء الدالة الموجودة في المكوّن الأب، وستظهر رسالة alert().

تمرير حدث onClick من المكوّن الابن إلى المكوّن الأب في React

أفضل الممارسات عند تمرير البيانات والأحداث

  • حافظ على وجود مصدر واحد للحقيقة Single Source of Truth داخل المكوّن الأب كلما أمكن.
  • استخدم أسماء واضحة للخصائص مثل childToParent وparentToChild لتسهيل قراءة الكود.
  • مرّر فقط ما يحتاجه المكوّن الابن، وتجنب إرسال كائنات كبيرة بلا ضرورة.
  • عند ازدياد تعقيد التطبيق، فكّر في استخدام Context API أو مكتبات إدارة الحالة مثل Redux.
  • افصل بين منطق الواجهة ومنطق البيانات حتى يبقى التطبيق أسهل في الاختبار والصيانة.

متى تستخدم هذا الأسلوب؟

يعد هذا النهج مناسباً جداً في الحالات التالية:

  1. عند الحاجة إلى تحديث واجهة المستخدم بناءً على حدث وقع داخل مكوّن فرعي.
  2. عند مشاركة بيانات بسيطة بين مكوّنات مرتبطة بعلاقة أب/ابن.
  3. عند تنفيذ نماذج الإدخال، الأزرار، النوافذ المنبثقة، أو عمليات الحذف والإضافة والتعديل.
  4. عند بناء واجهات صغيرة أو متوسطة لا تتطلب طبقة متقدمة لإدارة الحالة.

الخلاصة التقنية

تمرير البيانات والأحداث بين المكوّنات في React هو أساس بناء واجهات تفاعلية واضحة ومنظمة. إذا أردت إرسال البيانات من الأب إلى الابن، فاستخدم props مباشرة. وإذا أردت الإرسال من الابن إلى الأب، فالحل العملي هو تمرير دالة من الأب ثم استدعاؤها من الابن مع البيانات المطلوبة. هذا النمط بسيط وفعّال، ويمنحك تحكماً ممتازاً في تدفق البيانات قبل الانتقال إلى حلول أكثر تقدماً مثل Context API أو Redux.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *