العودة للمقالات

من الصفر إلى الجاهزية للإنتاج: بناء تطبيق كامل باستخدام React و Tailwind CSS و Supabase

المؤلفMajd Muhtaseb02‏/05‏/202515 دقيقة
من الصفر إلى الجاهزية للإنتاج: بناء تطبيق كامل باستخدام React و Tailwind CSS و Supabase

مقدمة

يشرح هذا الدليل كيفية إنشاء تطبيق كامل (Full-Stack) أساسي باستخدام React للواجهة الأمامية، و Tailwind CSS للتصميم، و Supabase كواجهة خلفية. سنغطي إعداد كل تقنية وربطها لبناء تطبيق بسيط لقائمة المهام.

إعداد المشروع

أولاً، قم بتهيئة مشروع React باستخدام Create React App:

npx create-react-app todo-app
cd todo-app

بعد ذلك، قم بتثبيت Tailwind CSS:

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

قم بتكوين tailwind.config.js:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./src/**/*.{js,jsx,ts,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

قم بتضمين توجيهات Tailwind في src/index.css:

@tailwind base;
@tailwind components;
@tailwind utilities;

أخيرًا ، قم بتثبيت مكتبة عميل Supabase:

npm install @supabase/supabase-js

إنشاء الواجهة الخلفية Supabase

  1. قم بإنشاء مشروع جديد على موقع Supabase (supabase.com).
  2. استرجع عنوان URL الخاص بـ Supabase ومفتاح API من إعدادات المشروع.
  3. قم بإنشاء جدول باسم todos مع الأعمدة التالية: id (UUID ، مفتاح أساسي) ، task (نص) ، و completed (منطقي ، القيمة الافتراضية هي خطأ).

ربط React بـ Supabase

قم بإنشاء ملف supabaseClient.js:

import { createClient } from '@supabase/supabase-js';

const supabaseUrl = process.env.REACT_APP_SUPABASE_URL;
const supabaseKey = process.env.REACT_APP_SUPABASE_ANON_KEY;
const supabase = createClient(supabaseUrl, supabaseKey);

export default supabase;

تذكر تعيين عنوان URL الخاص بـ Supabase ومفتاح API في ملف .env الخاص بك (قم بإنشاء واحد إذا لم يكن موجودًا):

REACT_APP_SUPABASE_URL=YOUR_SUPABASE_URL
REACT_APP_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY

بناء مكونات React

قم بإنشاء مكون TodoList.js:

import React, { useState, useEffect } from 'react';
import supabase from './supabaseClient';

function TodoList() {
  const [todos, setTodos] = useState([]);
  const [newTask, setNewTask] = useState('');

  useEffect(() => {
    fetchTodos();
  }, []);

  const fetchTodos = async () => {
    const { data, error } = await supabase
      .from('todos')
      .select('*')
      .order('id', { ascending: false });

    if (error) {
      console.error('Error fetching todos:', error);
    } else {
      setTodos(data);
    }
  };

  const addTodo = async () => {
    if (newTask.trim() === '') return;

    const { data, error } = await supabase
      .from('todos')
      .insert([{ task: newTask, completed: false }])
      .select();

    if (error) {
      console.error('Error adding todo:', error);
    } else {
      setTodos([...todos, data[0]]);
      setNewTask('');
    }
  };

    const toggleComplete = async (id, completed) => {
    const { error } = await supabase
      .from('todos')
      .update({ completed: !completed })
      .eq('id', id)

    if(error){
      console.log("error updating todo", error);
    } else {
        fetchTodos();
    }


  }

  return (
    <div className="max-w-md mx-auto p-4">
      <h1 className="text-2xl font-bold mb-4">قائمة المهام الخاصة بي</h1>
      <div className="flex mb-4">
        <input
          type="text"
          className="shadow appearance-none border rounded w-full py-2 px-3 mr-4 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
          placeholder="إضافة مهمة جديدة"
          value={newTask}
          onChange={(e) => setNewTask(e.target.value)}
        />
        <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" onClick={addTodo}>إضافة</button>
      </div>
      <ul>
        {todos.map((todo) => (
          <li key={todo.id} className="flex items-center justify-between py-2 border-b border-gray-200">
            <span className={todo.completed ? 'line-through text-gray-500' : 'text-gray-800'}>{todo.task}</span>
              <input
                type="checkbox"
                checked={todo.completed}
                onChange={() => toggleComplete(todo.id, todo.completed)}
                className="mr-2 leading-tight"
              />
          </li>
        ))}
      </ul>
    </div>
  );
}

export default TodoList;

قم بتحديث App.js لاستخدام مكون TodoList:

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

function App() {
  return (
    <div className="App">
      <TodoList />
    </div>
  );
}

export default App;

تشغيل التطبيق

ابدأ خادم تطوير React:

npm start

قم بزيارة http://localhost:3000 في متصفحك لرؤية تطبيق قائمة المهام الخاص بك.

خاتمة

يوفر هذا الدليل تطبيقًا أساسيًا لتطبيق كامل باستخدام React و Tailwind CSS و Supabase. يمكنك توسيع هذا أكثر من خلال إضافة ميزات مثل مصادقة المستخدم وهياكل بيانات أكثر تعقيدًا وتصميم أكثر تطوراً. جرب واستكشف قدرات كل تقنية لبناء تطبيقات أكثر قوة.