الانتقال للمحتوى الرئيسي

تطوير تطبيقات React.js المتقدمة مع TypeScript و Next.js

React.js, TypeScript, Next.js Linux متقدم 15219 مشاهدة 2025/12/07

دليل شامل لتطوير تطبيقات React.js المتقدمة مع TypeScript و Next.js

المقدمة

React.js هو أحد أشهر مكتبات JavaScript لبناء واجهات المستخدم، ومع إضافة TypeScript و Next.js يصبح قوياً بشكل لا يُقاوم. في هذا الدليل المفصل جداً، سنغطي كل ما تحتاجه لبناء تطبيقات React.js متقدمة مع شرح كل مفهوم والمنطق وراءه.

ما سنتعلم:

  • أساسيات TypeScript مع React
  • Next.js و Server-Side Rendering
  • إدارة الحالة المتقدمة
  • Testing مع Jest و React Testing Library
  • أدوات التطوير والتحسين
  • NPM Scripts والأتمتة
  • نشر التطبيقات

المتطلبات الأساسية:

  • معرفة جيدة بـ JavaScript (ES6+)
  • فهم أساسيات React.js
  • Node.js مثبت على النظام
  • محرر كود جيد (VS Code موصى به)

الخطوة 1: إعداد مشروع Next.js مع TypeScript

إنشاء مشروع جديد:

npx create-next-app@latest my-app --typescript --tailwind --eslint --app
cd my-app

فهم هيكل المشروع:

my-app/
├── app/                    # App Router (Next.js 13+)
│   ├── layout.tsx         # Root layout
│   ├── page.tsx          # Home page
│   └── globals.css       # Global styles
├── components/            # Reusable components
├── lib/                  # Utility functions
├── public/               # Static assets
├── types/                # TypeScript type definitions
├── utils/                # Helper functions
├── package.json
├── next.config.js
├── tailwind.config.js
└── tsconfig.json

إعداد TypeScript:

// tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "es6"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "baseUrl": ".",
    "paths": {
      "@/*": ["./*"],
      "@/components/*": ["./components/*"],
      "@/lib/*": ["./lib/*"],
      "@/types/*": ["./types/*"],
      "@/utils/*": ["./utils/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}

الخطوة 2: إنشاء أنواع البيانات (Types)

إنشاء أنواع أساسية:

// types/index.ts
export interface User {
  id: string;
  name: string;
  email: string;
  avatar?: string;
  createdAt: Date;
  updatedAt: Date;
}

export interface Post {
  id: string;
  title: string;
  content: string;
  author: User;
  tags: string[];
  published: boolean;
  createdAt: Date;
  updatedAt: Date;
}

export interface Comment {
  id: string;
  content: string;
  author: User;
  postId: string;
  createdAt: Date;
}

export interface ApiResponse {
  data: T;
  message?: string;
  success: boolean;
}

export interface PaginatedResponse {
  data: T[];
  pagination: {
    page: number;
    limit: number;
    total: number;
    totalPages: number;
  };
}

أنواع React المخصصة:

// types/react.ts
import { ReactNode, ComponentProps } from 'react';

// Extended component props
export type ComponentPropsWithChildren = T & {
  children?: ReactNode;
};

// Button variants
export type ButtonVariant = 'primary' | 'secondary' | 'danger' | 'success';
export type ButtonSize = 'sm' | 'md' | 'lg';

// Form field types
export interface FormFieldProps {
  name: string;
  label?: string;
  error?: string;
  required?: boolean;
  disabled?: boolean;
}

// API hook types
export interface UseQueryOptions {
  enabled?: boolean;
  refetchOnWindowFocus?: boolean;
  staleTime?: number;
}

export interface UseMutationOptions {
  onSuccess?: (data: TData) => void;
  onError?: (error: Error) => void;
  onSettled?: () => void;
}

الخطوة 3: إنشاء Hooks مخصصة

Hook للـ API calls:

// lib/hooks/useApi.ts
import { useState, useEffect, useCallback } from 'react';
import { ApiResponse } from '@/types';

interface UseApiOptions {
  immediate?: boolean;
}

export function useApi(
  apiCall: () => Promise>,
  options: UseApiOptions = {}
) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const execute = useCallback(async () => {
    try {
      setLoading(true);
      setError(null);
      const response = await apiCall();
      if (response.success) {
        setData(response.data);
      } else {
        setError(response.message || 'An error occurred');
      }
    } catch (err) {
      setError(err instanceof Error ? err.message : 'An error occurred');
    } finally {
      setLoading(false);
    }
  }, [apiCall]);

  useEffect(() => {
    if (options.immediate) {
      execute();
    }
  }, [execute, options.immediate]);

  return { data, loading, error, execute, refetch: execute };
}

Hook للـ Local Storage:

// lib/hooks/useLocalStorage.ts
import { useState, useEffect } from 'react';

export function useLocalStorage(
  key: string,
  initialValue: T
): [T, (value: T | ((val: T) => T)) => void] {
  const [storedValue, setStoredValue] = useState(() => {
    if (typeof window === 'undefined') {
      return initialValue;
    }
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error(`Error reading localStorage key "${key}":`, error);
      return initialValue;
    }
  });

  const setValue = (value: T | ((val: T) => T)) => {
    try {
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      if (typeof window !== 'undefined') {
        window.localStorage.setItem(key, JSON.stringify(valueToStore));
      }
    } catch (error) {
      console.error(`Error setting localStorage key "${key}":`, error);
    }
  };

  return [storedValue, setValue];
}

الخطوة 4: إنشاء مكونات أساسية (Base Components)

مكون Button:

// components/ui/Button.tsx
import { forwardRef } from 'react';
import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@/lib/utils';

const buttonVariants = cva(
  'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background',
  {
    variants: {
      variant: {
        default: 'bg-primary text-primary-foreground hover:bg-primary/90',
        destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
        outline: 'border border-input hover:bg-accent hover:text-accent-foreground',
        secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
        ghost: 'hover:bg-accent hover:text-accent-foreground',
        link: 'underline-offset-4 hover:underline text-primary',
      },
      size: {
        default: 'h-10 py-2 px-4',
        sm: 'h-9 px-3 rounded-md',
        lg: 'h-11 px-8 rounded-md',
        icon: 'h-10 w-10',
      },
    },
    defaultVariants: {
      variant: 'default',
      size: 'default',
    },
  }
);

export interface ButtonProps
  extends React.ButtonHTMLAttributes,
    VariantProps {
  asChild?: boolean;
}

const Button = forwardRef(
  ({ className, variant, size, asChild = false, ...props }, ref) => {
    return (
      

مكون Input:

// components/ui/Input.tsx
import * as React from 'react';
import { cn } from '@/lib/utils';

export interface InputProps
  extends React.InputHTMLAttributes {}

const Input = React.forwardRef(
  ({ className, type, ...props }, ref) => {
    return (
      
    );
  }
);
Input.displayName = 'Input';

export { Input };

الخطوة 5: إعداد إدارة الحالة مع Zustand

تثبيت Zustand:

npm install zustand

إنشاء store للمستخدم:

// lib/stores/userStore.ts
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
import { User } from '@/types';

interface UserState {
  user: User | null;
  isAuthenticated: boolean;
  login: (user: User) => void;
  logout: () => void;
  updateUser: (updates: Partial) => void;
}

export const useUserStore = create()(
  devtools(
    persist(
      (set, get) => ({
        user: null,
        isAuthenticated: false,

        login: (user: User) => {
          set({ user, isAuthenticated: true });
        },

        logout: () => {
          set({ user: null, isAuthenticated: false });
        },

        updateUser: (updates: Partial) => {
          const currentUser = get().user;
          if (currentUser) {
            set({ user: { ...currentUser, ...updates } });
          }
        },
      }),
      {
        name: 'user-storage',
      }
    ),
    {
      name: 'user-store',
    }
  )
);

Store للإعدادات:

// lib/stores/settingsStore.ts
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';

interface SettingsState {
  theme: 'light' | 'dark' | 'system';
  language: string;
  notifications: boolean;
  setTheme: (theme: 'light' | 'dark' | 'system') => void;
  setLanguage: (language: string) => void;
  toggleNotifications: () => void;
}

export const useSettingsStore = create()(
  devtools(
    persist(
      (set) => ({
        theme: 'system',
        language: 'ar',
        notifications: true,

        setTheme: (theme) => set({ theme }),
        setLanguage: (language) => set({ language }),
        toggleNotifications: () => set((state) => ({ notifications: !state.notifications })),
      }),
      {
        name: 'settings-storage',
      }
    ),
    {
      name: 'settings-store',
    }
  )
);

الخطوة 6: إعداد API Routes

إنشاء API route للمستخدمين:

// app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';

const createUserSchema = z.object({
  name: z.string().min(2).max(50),
  email: z.string().email(),
  password: z.string().min(8),
});

export async function GET(request: NextRequest) {
  try {
    // Get users from database
    const users = await getUsers();

    return NextResponse.json({
      data: users,
      success: true,
    });
  } catch (error) {
    return NextResponse.json(
      { error: 'Failed to fetch users', success: false },
      { status: 500 }
    );
  }
}

export async function POST(request: NextRequest) {
  try {
    const body = await request.json();
    const validatedData = createUserSchema.parse(body);

    // Create user in database
    const user = await createUser(validatedData);

    return NextResponse.json(
      {
        data: user,
        message: 'User created successfully',
        success: true,
      },
      { status: 201 }
    );
  } catch (error) {
    if (error instanceof z.ZodError) {
      return NextResponse.json(
        { error: error.errors, success: false },
        { status: 400 }
      );
    }

    return NextResponse.json(
      { error: 'Failed to create user', success: false },
      { status: 500 }
    );
  }
}

API route لمنشور واحد:

// app/api/users/[id]/route.ts
import { NextRequest, NextResponse } from 'next/server';

interface RouteParams {
  params: {
    id: string;
  };
}

export async function GET(
  request: NextRequest,
  { params }: RouteParams
) {
  try {
    const user = await getUserById(params.id);

    if (!user) {
      return NextResponse.json(
        { error: 'User not found', success: false },
        { status: 404 }
      );
    }

    return NextResponse.json({
      data: user,
      success: true,
    });
  } catch (error) {
    return NextResponse.json(
      { error: 'Failed to fetch user', success: false },
      { status: 500 }
    );
  }
}

export async function PUT(
  request: NextRequest,
  { params }: RouteParams
) {
  try {
    const body = await request.json();
    const updatedUser = await updateUser(params.id, body);

    return NextResponse.json({
      data: updatedUser,
      message: 'User updated successfully',
      success: true,
    });
  } catch (error) {
    return NextResponse.json(
      { error: 'Failed to update user', success: false },
      { status: 500 }
    );
  }
}

export async function DELETE(
  request: NextRequest,
  { params }: RouteParams
) {
  try {
    await deleteUser(params.id);

    return NextResponse.json({
      message: 'User deleted successfully',
      success: true,
    });
  } catch (error) {
    return NextResponse.json(
      { error: 'Failed to delete user', success: false },
      { status: 500 }
    );
  }
}

الخطوة 7: إعداد Testing

تثبيت testing libraries:

npm install --save-dev @testing-library/react @testing-library/jest-dom @testing-library/user-event jest-environment-jsdom

إعداد Jest:

// jest.config.js
const nextJest = require('next/jest');

const createJestConfig = nextJest({
  dir: './',
});

const customJestConfig = {
  setupFilesAfterEnv: ['/jest.setup.js'],
  moduleNameMapping: {
    '^@/(.*)$': '/$1',
  },
  testEnvironment: 'jest-environment-jsdom',
};

module.exports = createJestConfig(customJestConfig);

ملف setup للاختبارات:

// jest.setup.js
import '@testing-library/jest-dom';

اختبار مكون Button:

// components/ui/Button.test.tsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Button } from './Button';

describe('Button', () => {
  it('renders with default props', () => {
    render();
    const button = screen.getByRole('button', { name: /click me/i });
    expect(button).toBeInTheDocument();
  });

  it('calls onClick when clicked', async () => {
    const user = userEvent.setup();
    const handleClick = jest.fn();
    render();

    await user.click(screen.getByRole('button', { name: /click me/i }));
    expect(handleClick).toHaveBeenCalledTimes(1);
  });

  it('is disabled when disabled prop is true', () => {
    render();
    const button = screen.getByRole('button', { name: /click me/i });
    expect(button).toBeDisabled();
  });

  it('applies correct variant classes', () => {
    render();
    const button = screen.getByRole('button', { name: /delete/i });
    expect(button).toHaveClass('bg-destructive');
  });
});

الخطوة 8: تحسين الأداء

استخدام React.memo:

// components/UserCard.tsx
import { memo } from 'react';
import { User } from '@/types';

interface UserCardProps {
  user: User;
  onEdit?: (user: User) => void;
  onDelete?: (userId: string) => void;
}

const UserCard = memo(({ user, onEdit, onDelete }) => {
  return (
    

{user.name}

{user.email}

{onEdit && ( )} {onDelete && ( )}
); }); UserCard.displayName = 'UserCard'; export { UserCard };

استخدام useMemo و useCallback:

// components/UserList.tsx
import { useMemo, useCallback } from 'react';
import { User } from '@/types';
import { UserCard } from './UserCard';

interface UserListProps {
  users: User[];
  searchTerm: string;
  onEditUser: (user: User) => void;
  onDeleteUser: (userId: string) => void;
}

export function UserList({
  users,
  searchTerm,
  onEditUser,
  onDeleteUser,
}: UserListProps) {
  const filteredUsers = useMemo(() => {
    return users.filter((user) =>
      user.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
      user.email.toLowerCase().includes(searchTerm.toLowerCase())
    );
  }, [users, searchTerm]);

  const handleEditUser = useCallback(
    (user: User) => {
      onEditUser(user);
    },
    [onEditUser]
  );

  const handleDeleteUser = useCallback(
    (userId: string) => {
      onDeleteUser(userId);
    },
    [onDeleteUser]
  );

  return (
    
{filteredUsers.map((user) => ( ))}
); }

الخطوة 9: إعداد CI/CD مع GitHub Actions

إنشاء workflow للاختبارات:

// .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

jobs:
  test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [16.x, 18.x]

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run linting
        run: npm run lint

      - name: Run type checking
        run: npm run type-check

      - name: Run tests
        run: npm run test:ci

      - name: Build application
        run: npm run build

  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 18.x
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build application
        run: npm run build

      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}

الخطوة 10: إعداد النشر

إعداد Vercel:

npm i -g vercel
vercel --prod

إعداد environment variables:

// .env.local
NEXT_PUBLIC_API_URL=https://api.example.com
DATABASE_URL=postgresql://username:password@localhost:5432/myapp
JWT_SECRET=your-secret-key-here
NEXTAUTH_SECRET=your-nextauth-secret
NEXTAUTH_URL=http://localhost:3000

إعداد build script:

// package.json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "lint:fix": "next lint --fix",
    "type-check": "tsc --noEmit",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:ci": "jest --ci --coverage",
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build"
  }
}

خاتمة

تهانينا! لقد نجحت في إعداد بيئة تطوير متكاملة لتطبيقات React.js المتقدمة مع TypeScript و Next.js. الآن لديك جميع الأدوات والمعارف المطلوبة لبناء تطبيقات ويب حديثة وقوية.

الميزات المضافة:

  • TypeScript للتحقق من الأنواع
  • Next.js للـ SSR والتطبيقات السريعة
  • Zustand لإدارة الحالة
  • Testing شامل مع Jest
  • CI/CD مع GitHub Actions
  • UI Components قابلة للإعادة
  • API Routes محمية
  • تحسينات الأداء

خطوات التطوير المستقبلية:

  • إضافة Storybook للوثائق
  • تكامل مع GraphQL
  • إضافة PWA features
  • تحسين SEO
  • إضافة Real-time features

من خلال

Mohannad Hassounah

مشرف

معلومات الشرح

البرنامج: React.js, TypeScript, Next.js
نظام التشغيل: Linux
المستوى: متقدم