React

React Image Cropper & Editor

Build an image editing tool with crop, rotate, filters, and canvas-based export.

ReactCanvasImage EditorCrop

Thumbnail for React Image Cropper & Editor

Overview

Build an image editing tool with crop, rotate, filters, and canvas-based export.

Project Setup

bash
npx create-react-app react-13-react-image-cropper-editor --template typescript
cd react-13-react-image-cropper-editor
npm install canvas image-editor crop

Component Architecture

tsx
import React, { useState, useCallback, useMemo } from 'react';

interface Item {
  id: string;
  title: string;
  status: 'active' | 'completed' | 'archived';
  createdAt: Date;
}

interface ReactProps {
  initialItems?: Item[];
  onUpdate?: (items: Item[]) => void;
}

export default function ReactManager({
  initialItems = [],
  onUpdate,
}: ReactProps) {
  const [items, setItems] = useState<Item[]>(initialItems);
  const [filter, setFilter] = useState<string>('all');

  const filteredItems = useMemo(
    () => filter === 'all' ? items : items.filter(i => i.status === filter),
    [items, filter]
  );

  const addItem = useCallback((title: string) => {
    const newItem: Item = {
      id: crypto.randomUUID(),
      title,
      status: 'active',
      createdAt: new Date(),
    };
    const updated = [...items, newItem];
    setItems(updated);
    onUpdate?.(updated);
  }, [items, onUpdate]);

  const updateStatus = useCallback((id: string, status: Item['status']) => {
    const updated = items.map(item =>
      item.id === id ? { ...item, status } : item
    );
    setItems(updated);
    onUpdate?.(updated);
  }, [items, onUpdate]);

  return (
    <div className="max-w-2xl mx-auto p-6">
      <h2 className="text-2xl font-bold mb-4">React Image Cropper & Editor</h2>

      <div className="flex gap-2 mb-6">
        {['all', 'active', 'completed'].map(f => (
          <button
            key={f}
            onClick={() => setFilter(f)}
            className={\`px-4 py-2 rounded-lg \${
              filter === f ? 'bg-indigo-600 text-white' : 'bg-gray-100'
            }\`}
          >
            {f.charAt(0).toUpperCase() + f.slice(1)}
          </button>
        ))}
      </div>

      <ul className="space-y-3">
        {filteredItems.map(item => (
          <li key={item.id} className="flex items-center justify-between p-4 bg-white rounded-lg shadow">
            <span className={item.status === 'completed' ? 'line-through text-gray-400' : ''}>
              {item.title}
            </span>
            <button
              onClick={() => updateStatus(item.id, item.status === 'active' ? 'completed' : 'active')}
              className="text-sm text-indigo-600 hover:text-indigo-800"
            >
              {item.status === 'active' ? 'Complete' : 'Reopen'}
            </button>
          </li>
        ))}
      </ul>

      <p className="mt-4 text-sm text-gray-500">
        Showing {filteredItems.length} of {items.length} items
      </p>
    </div>
  );
}

Custom Hook

tsx
import { useState, useEffect } from 'react';

function useLocalStorage<T>(key: string, initialValue: T) {
  const [value, setValue] = useState<T>(() => {
    try {
      const stored = localStorage.getItem(key);
      return stored ? JSON.parse(stored) : initialValue;
    } catch {
      return initialValue;
    }
  });

  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue] as const;
}

Key Features

- Built with React and TypeScript for type safety - Uses \useMemo\ and \useCallback\ for performance optimization - Responsive design with Tailwind CSS - React, Canvas, Image Editor, Crop integration

Related Projects

Comments (0)

Leave a Comment

No comments yet. Be the first to comment!