لماذا لا تظهر صورك المحلية في React؟ دليل شامل لحل مشكلة المسارات

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

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

/src
  /components
    - component1
    - component2
  /img
    - img1.jpg
    - img2.png

وتحاول الوصول إلى الصور الموجودة في مجلد /img من داخل component2. قد تكون قد جربت مسارات مثل ../img/img1.jpg أو ..img/img1.jpg، ولكنك تتلقى خطأً مشابهًا لـ Error: Cannot find module '<path>'. فما الذي يحدث بالضبط؟

فهم آلية عمل create-react-app مع الأصول

مثل معظم المطورين، ربما استخدمت أداة create-react-app لإنشاء مشروع React الخاص بك بسرعة. في هذه الحالة، يمكن أن يكون استخدام المسارات النسبية (relative paths) معقدًا بعض الشيء، وذلك لأن create-react-app يقوم ببناء ملفات HTML و CSS و JavaScript في مجلد إخراج محدد، والذي عادةً ما يكون /build أو /public بعد عملية البناء. هذا المجلد الناتج هو الذي يتم تقديمه للمتصفح، ويكون هيكله عادةً كالتالي:

/public
  - index.html
  - bundle.js
  - style.css

عندما يتم بناء المشروع، يصبح مجلد /public هو الدليل الجذر (root directory) الذي تخدم منه جميع الملفات. هذا يعني أن أي مسار نسبي تكتبه داخل مكوناتك في مجلد /src سيتم تفسيره بناءً على هذا الدليل الجذر بعد عملية البناء، وليس بناءً على الهيكل الأصلي لمجلد /src. هذا هو السبب الرئيسي وراء فشل محاولاتك في العثور على الصور باستخدام المسارات النسبية التقليدية.

الحلول الفعالة لمشكلة تحميل الصور في React

هناك عدة طرق لاستخدام الصور والأصول الأخرى مع create-react-app، وكل طريقة لها مزاياها وعيوبها. سنستعرض هنا طريقتين رئيسيتين:

الخيار الأول: استخدام مجلد public كجذر للمشروع

إحدى أسهل الطرق وأكثرها شيوعًا هي وضع صورك مباشرة داخل مجلد /public. عندما يتم بناء مشروعك، يعمل مجلد /public كدليل جذر، مما يعني أنه يمكنك الإشارة إلى أي ملف بداخله مباشرة باستخدام مسار يبدأ من الجذر. على سبيل المثال، إذا كانت لديك صورة my-image.jpg داخل /public/images، يمكنك الوصول إليها في مكون React الخاص بك باستخدام المسار /images/my-image.jpg.

المزايا:

  • السهولة: طريقة مباشرة وبسيطة للملفات الثابتة.
  • الوصول المباشر: يمكن الوصول إليها مباشرة عبر المسار المطلق من جذر التطبيق.

العيوب:

  • عدم التحقق وقت البناء: لن يتم التحقق من وجود الصورة أو صحة مسارها أثناء عملية البناء، مما قد يؤدي إلى ظهور صور معطلة (broken images) في الإنتاج إذا كان هناك خطأ إملائي في المسار.
  • عدم التحسين: لا يتم معالجة هذه الصور بواسطة أدوات بناء مثل Webpack، مما يعني أنها لن تستفيد من تحسينات مثل ضغط الصور أو إضافة تجزئات فريدة لأغراض التخزين المؤقت (caching).

يمكنك قراءة المزيد حول إضافة الصور أو الأصول الأخرى في وثائق Create React App الرسمية.

الخيار الثاني: استيراد الصور باستخدام import

إذا ألقيت نظرة على وثائق create-react-app، ستلاحظ أن الكود يتضمن عبارات import لتحميل الأصول مثل الصور والخطوط. يعد الاستيراد مفيدًا بشكل خاص عندما يكون الأصل، في هذه الحالة صورة، موجودًا في نفس الدليل أو بالقرب من المكون الذي يستخدمه، ولن يتم استخدامه في أي مكان آخر في التطبيق. على سبيل المثال، إذا كان لديك مكون إدخال بأزرار تستخدم صور SVG لأيقونات الإعجاب وعدم الإعجاب.

عندما تقوم باستيراد صورة، يقوم Webpack بمعالجتها كجزء من حزمة التطبيق. يتم استبدال مسار الاستيراد بعنوان URL فريد للصورة في حزمة الإخراج، مما يضمن أن الصورة متاحة بشكل صحيح.

المزايا:

  • التحقق وقت البناء: إحدى المزايا الكبيرة لاستخدام import هي أنه سيتم إلقاء خطأ أثناء وقت البناء إذا كان هناك خطأ إملائي في المسار أو لم يتم العثور على الصورة. يساعد هذا النوع من التحقق في ضمان عدم رؤية المستخدمين لصور معطلة قد تكون تسربت إلى الإنتاج.
  • التحسين: يتم معالجة الصور المستوردة بواسطة Webpack، مما يسمح بتحسينات مثل ضغط الصور، وتصغير حجمها، وإضافة تجزئات فريدة لأسماء الملفات لتحسين التخزين المؤقت في المتصفح.
  • التجميع (Bundling): يتم تضمين الصورة مباشرة في حزمة JavaScript، مما يقلل من طلبات الشبكة الإضافية.

مثال على استخدام import في مكون React:

لنفترض أن لديك مصفوفة من كائنات الصور (imgArr) وكل كائن يحتوي على خاصية url تشير إلى مسار الصورة. يمكنك استخدام require() داخل خاصية src لوسم <img> لتحميل الصورة ديناميكيًا:

import React, { Component, useState, useEffect } from 'react';
import { render } from 'react-dom';
import { useTransition, animated, config } from "react-spring";
import imgArr from './images'; // افترض أن هذا الملف يحتوي على مصفوفة مسارات الصور
import '../App.css';

const Slideshow = () => {
  const [index, set] = useState(0);
  const transitions = useTransition(imgArr[index], item => item.id, {
    from: { opacity: 0 },
    enter: { opacity: 1 },
    leave: { opacity: 0 },
    config: config.molasses,
  });

  useEffect(() => void setInterval(() => set(state => (state + 1) % 4), 2000), []);

  return transitions.map(({ item, props, key }) => (
    <animated.div key={key} className="bg" style={{ ...props, slideshowContainerStyle }} >
      <img className="img" src={require(item.url)} alt="صورة لعرض الشرائح" />
    </animated.div>
  ));
}

const slideshowContainerStyle = {
  width: '80%',
  height: '300px'
};

export default Slideshow;

في هذا المثال، يتم استخدام require(item.url) لتحميل الصورة ديناميكيًا. require() هي دالة خاصة بـ CommonJS (التي يستخدمها Webpack) تسمح بتحميل الوحدات (modules) بشكل متزامن. عندما يتم تمرير مسار الصورة إليها، يقوم Webpack بمعالجتها وتوفير عنوان URL الصحيح الذي يمكن للمتصفح الوصول إليه.

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

تعد مشكلة عدم ظهور الصور المحلية في تطبيقات React التي تم إنشاؤها باستخدام create-react-app من التحديات الشائعة للمطورين الجدد. يكمن جوهر المشكلة في كيفية قيام create-react-app ببناء المشروع وتحديد الدليل الجذر لخدمة الأصول. لفهم الحلول، يجب استيعاب أن مجلد /public يصبح هو الدليل الجذر بعد البناء.

لحل هذه المشكلة، لديك خياران رئيسيان: إما وضع الصور الثابتة التي لا تتطلب معالجة خاصة في مجلد /public والوصول إليها بمسارات مطلقة، أو استخدام عبارات import لتحميل الصور التي ترتبط بمكونات معينة. الخيار الثاني (الاستيراد) هو المفضل لمعظم السيناريوهات لأنه يوفر تحسينات في الأداء، وتحققًا من الأخطاء وقت البناء، وتكاملًا أفضل مع أدوات Webpack. اختيار الطريقة الصحيحة يعتمد على طبيعة الصورة واستخدامها في مشروعك، ولكن فهم آلياتها يضمن تجربة تطوير سلسة وخالية من الأخطاء البصرية.

اترك تعليقاً

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