affaan-m/ECC

frontend-patterns

React, Next.js, state yönetimi, performans optimizasyonu ve UI en iyi uygulamaları için frontend geliştirme kalıpları.

66CollectingNetwork access
See how to use itView GitHub source
npx skills add https://github.com/affaan-m/ECC --skill "docs/tr/skills/frontend-patterns"
Automated source guideDocumentationDeep source

Source checked Jul 28, 2026·Refresh due Oct 26, 2026

Reorganized from the pinned upstream SKILL.md

Source-grounded documentation guide: frontend-patterns

React, Next.js ve performanslı kullanıcı arayüzleri için modern frontend kalıpları.

npx skills add https://github.com/affaan-m/ECC --skill "docs/tr/skills/frontend-patterns"
Check the pinned source

The pinned source contains enough sections and task detail for a source-grounded deep guide; automated content is still not an independent test.

1,543 source words · 23 usable sections

Documentation workflow

Read frontend-patterns through these 5 source sections

Sections are extracted automatically from the pinned SKILL.md and link back to the source.

01

Ne Zaman Aktifleştirmelisiniz

React bileşenleri oluştururken (composition, props, rendering)

SKILL.md · Ne Zaman Aktifleştirmelisiniz
React bileşenleri oluştururken (composition, props, rendering)State yönetirken (useState, useReducer, Zustand, Context)Veri çekme implementasyonu (SWR, React Query, server components)
02

Bileşen Kalıpları

Review the “Bileşen Kalıpları” section in the pinned source before continuing.

SKILL.md · Bileşen Kalıpları
Review and apply the “Bileşen Kalıpları” source section.
03

Kalıtım Yerine Composition

Review the “Kalıtım Yerine Composition” section in the pinned source before continuing.

SKILL.md · Kalıtım Yerine Composition
Review and apply the “Kalıtım Yerine Composition” source section.
04

Compound Components

Review the “Compound Components” section in the pinned source before continuing.

SKILL.md · Compound Components
Review and apply the “Compound Components” source section.
05

Render Props Kalıbı

Review the “Render Props Kalıbı” section in the pinned source before continuing.

SKILL.md · Render Props Kalıbı
Review and apply the “Render Props Kalıbı” source section.

SkillSignal prompt templates

Provide the task, context, and acceptance criteria

These prompts were written by SkillSignal from the source structure; they are not upstream text.

Source-grounded prompt

Use for a documentation task while explicitly checking the source sections.

Use frontend-patterns for this documentation task: [task]. Inputs and constraints: [details]. Work through these pinned SKILL.md sections: “Ne Zaman Aktifleştirmelisiniz”, “Bileşen Kalıpları”, “Kalıtım Yerine Composition”, “Compound Components”, “Render Props Kalıbı”. Cite the concrete requirements that shape each step, do not invent capabilities absent from the source, and verify the result against: [acceptance criteria].

Documentation checklist

Verify each item before delivery

The source section “Ne Zaman Aktifleştirmelisiniz” has been checked.

The source section “Bileşen Kalıpları” has been checked.

The source section “Kalıtım Yerine Composition” has been checked.

The source section “Compound Components” has been checked.

Static permission evidence

Inspect the exact source lines that triggered a signal

These are source excerpts matched by deterministic rules, not findings of malicious behavior, safety, or actual execution.

Choose a different workflow

When another Skill is the better fit

FAQ

What does the frontend-patterns source document cover?

React, Next.js ve performanslı kullanıcı arayüzleri için modern frontend kalıpları.

How do I install frontend-patterns?

The source record exposes this install command: npx skills add https://github.com/affaan-m/ECC --skill "docs/tr/skills/frontend-patterns". Inspect the command and pinned source before running it.

Which permission-related actions were detected?

Static rules flagged network in the source; the page lists the matching lines and excerpts.

Repository stars
234,327
Repository forks
35,711
Quality
66/100
Source repository last pushed

Quality breakdown

Based on traceable docs and repository signals; stars are not treated as quality.

66/100
Documentation25/30
Specificity11/25
Maintenance20/20
Trust signals10/25
View original Skill.mdThis page is parsed directly from the repository SKILL.md without editorial rewriting. Collected: Jul 28, 2026 · about 1 min

Frontend Geliştirme Kalıpları

React, Next.js ve performanslı kullanıcı arayüzleri için modern frontend kalıpları.

Ne Zaman Aktifleştirmelisiniz

  • React bileşenleri oluştururken (composition, props, rendering)
  • State yönetirken (useState, useReducer, Zustand, Context)
  • Veri çekme implementasyonu (SWR, React Query, server components)
  • Performans optimize ederken (memoization, virtualization, code splitting)
  • Formlarla çalışırken (validation, controlled inputs, Zod schemas)
  • Client-side routing ve navigasyon işlerken
  • Erişilebilir, responsive UI kalıpları oluştururken

Bileşen Kalıpları

Kalıtım Yerine Composition

// PASS: İYİ: Bileşen composition
interface CardProps {
  children: React.ReactNode
  variant?: 'default' | 'outlined'
}

export function Card({ children, variant = 'default' }: CardProps) {
  return <div className={`card card-${variant}`}>{children}</div>
}

export function CardHeader({ children }: { children: React.ReactNode }) {
  return <div className="card-header">{children}</div>
}

export function CardBody({ children }: { children: React.ReactNode }) {
  return <div className="card-body">{children}</div>
}

// Kullanım
<Card>
  <CardHeader>Başlık</CardHeader>
  <CardBody>İçerik</CardBody>
</Card>

Compound Components

interface TabsContextValue {
  activeTab: string
  setActiveTab: (tab: string) => void
}

const TabsContext = createContext<TabsContextValue | undefined>(undefined)

export function Tabs({ children, defaultTab }: {
  children: React.ReactNode
  defaultTab: string
}) {
  const [activeTab, setActiveTab] = useState(defaultTab)

  return (
    <TabsContext.Provider value={{ activeTab, setActiveTab }}>
      {children}
    </TabsContext.Provider>
  )
}

export function TabList({ children }: { children: React.ReactNode }) {
  return <div className="tab-list">{children}</div>
}

export function Tab({ id, children }: { id: string, children: React.ReactNode }) {
  const context = useContext(TabsContext)
  if (!context) throw new Error('Tab must be used within Tabs')

  return (
    <button
      className={context.activeTab === id ? 'active' : ''}
      onClick={() => context.setActiveTab(id)}
    >
      {children}
    </button>
  )
}

// Kullanım
<Tabs defaultTab="overview">
  <TabList>
    <Tab id="overview">Genel Bakış</Tab>
    <Tab id="details">Detaylar</Tab>
  </TabList>
</Tabs>

Render Props Kalıbı

interface DataLoaderProps<T> {
  url: string
  children: (data: T | null, loading: boolean, error: Error | null) => React.ReactNode
}

export function DataLoader<T>({ url, children }: DataLoaderProps<T>) {
  const [data, setData] = useState<T | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<Error | null>(null)

  useEffect(() => {
    fetch(url)
      .then(res => res.json())
      .then(setData)
      .catch(setError)
      .finally(() => setLoading(false))
  }, [url])

  return <>{children(data, loading, error)}</>
}

// Kullanım
<DataLoader<Market[]> url="/api/markets">
  {(markets, loading, error) => {
    if (loading) return <Spinner />
    if (error) return <Error error={error} />
    return <MarketList markets={markets!} />
  }}
</DataLoader>

Özel Hook Kalıpları

State Yönetimi Hook'u

export function useToggle(initialValue = false): [boolean, () => void] {
  const [value, setValue] = useState(initialValue)

  const toggle = useCallback(() => {
    setValue(v => !v)
  }, [])

  return [value, toggle]
}

// Kullanım
const [isOpen, toggleOpen] = useToggle()

Async Veri Çekme Hook'u

interface UseQueryOptions<T> {
  onSuccess?: (data: T) => void
  onError?: (error: Error) => void
  enabled?: boolean
}

export function useQuery<T>(
  key: string,
  fetcher: () => Promise<T>,
  options?: UseQueryOptions<T>
) {
  const [data, setData] = useState<T | null>(null)
  const [error, setError] = useState<Error | null>(null)
  const [loading, setLoading] = useState(false)

  // Çağıranlar satır içi fonksiyonlar ve nesne literalleri geçirse bile
  // refetch'in referans olarak kararlı kalması için en güncel fetcher/options
  // değerlerini ref'lerde tutun. Bu olmadan her render yeni bir refetch
  // oluşturur ve aşağıdaki effect her state güncellemesinden sonra yeniden
  // çalışır - sonsuz bir fetch döngüsü.
  const fetcherRef = useRef(fetcher)
  const optionsRef = useRef(options)
  useEffect(() => {
    fetcherRef.current = fetcher
    optionsRef.current = options
  })

  const refetch = useCallback(async () => {
    setLoading(true)
    setError(null)

    try {
      const result = await fetcherRef.current()
      setData(result)
      optionsRef.current?.onSuccess?.(result)
    } catch (err) {
      const error = err as Error
      setError(error)
      optionsRef.current?.onError?.(error)
    } finally {
      setLoading(false)
    }
  }, [])

  const enabled = options?.enabled !== false

  useEffect(() => {
    if (enabled) {
      refetch()
    }
  }, [key, enabled, refetch])

  return { data, error, loading, refetch }
}

// Kullanım
const { data: markets, loading, error, refetch } = useQuery(
  'markets',
  () => fetch('/api/markets').then(r => r.json()),
  {
    onSuccess: data => console.log('Getirilen', data.length, 'market'),
    onError: err => console.error('Başarısız:', err)
  }
)

Debounce Hook'u

export function useDebounce<T>(value: T, delay: number): T {
  const [debouncedValue, setDebouncedValue] = useState<T>(value)

  useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value)
    }, delay)

    return () => clearTimeout(handler)
  }, [value, delay])

  return debouncedValue
}

// Kullanım
const [searchQuery, setSearchQuery] = useState('')
const debouncedQuery = useDebounce(searchQuery, 500)

useEffect(() => {
  if (debouncedQuery) {
    performSearch(debouncedQuery)
  }
}, [debouncedQuery])

State Yönetimi Kalıpları

Context + Reducer Kalıbı

interface State {
  markets: Market[]
  selectedMarket: Market | null
  loading: boolean
}

type Action =
  | { type: 'SET_MARKETS'; payload: Market[] }
  | { type: 'SELECT_MARKET'; payload: Market }
  | { type: 'SET_LOADING'; payload: boolean }

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case 'SET_MARKETS':
      return { ...state, markets: action.payload }
    case 'SELECT_MARKET':
      return { ...state, selectedMarket: action.payload }
    case 'SET_LOADING':
      return { ...state, loading: action.payload }
    default:
      return state
  }
}

const MarketContext = createContext<{
  state: State
  dispatch: Dispatch<Action>
} | undefined>(undefined)

export function MarketProvider({ children }: { children: React.ReactNode }) {
  const [state, dispatch] = useReducer(reducer, {
    markets: [],
    selectedMarket: null,
    loading: false
  })

  return (
    <MarketContext.Provider value={{ state, dispatch }}>
      {children}
    </MarketContext.Provider>
  )
}

export function useMarkets() {
  const context = useContext(MarketContext)
  if (!context) throw new Error('useMarkets must be used within MarketProvider')
  return context
}

Performans Optimizasyonu

Memoization

// PASS: Pahalı hesaplamalar için useMemo
// Sıralamadan önce kopyalayın - Array.prototype.sort yerinde değiştirir
const sortedMarkets = useMemo(() => {
  return [...markets].sort((a, b) => b.volume - a.volume)
}, [markets])

// PASS: Alt bileşenlere geçirilen fonksiyonlar için useCallback
const handleSearch = useCallback((query: string) => {
  setSearchQuery(query)
}, [])

// PASS: Pure bileşenler için React.memo
export const MarketCard = React.memo<MarketCardProps>(({ market }) => {
  return (
    <div className="market-card">
      <h3>{market.name}</h3>
      <p>{market.description}</p>
    </div>
  )
})

Code Splitting ve Lazy Loading

import { lazy, Suspense } from 'react'

// PASS: Ağır bileşenleri lazy yükle
const HeavyChart = lazy(() => import('./HeavyChart'))
const ThreeJsBackground = lazy(() => import('./ThreeJsBackground'))

export function Dashboard() {
  return (
    <div>
      <Suspense fallback={<ChartSkeleton />}>
        <HeavyChart data={data} />
      </Suspense>

      <Suspense fallback={null}>
        <ThreeJsBackground />
      </Suspense>
    </div>
  )
}

Uzun Listeler için Virtualization

import { useVirtualizer } from '@tanstack/react-virtual'

export function VirtualMarketList({ markets }: { markets: Market[] }) {
  const parentRef = useRef<HTMLDivElement>(null)

  const virtualizer = useVirtualizer({
    count: markets.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 100,  // Tahmini satır yüksekliği
    overscan: 5  // Ekstra render edilecek öğeler
  })

  return (
    <div ref={parentRef} style={{ height: '600px', overflow: 'auto' }}>
      <div
        style={{
          height: `${virtualizer.getTotalSize()}px`,
          position: 'relative'
        }}
      >
        {virtualizer.getVirtualItems().map(virtualRow => (
          <div
            key={virtualRow.index}
            style={{
              position: 'absolute',
              top: 0,
              left: 0,
              width: '100%',
              height: `${virtualRow.size}px`,
              transform: `translateY(${virtualRow.start}px)`
            }}
          >
            <MarketCard market={markets[virtualRow.index]} />
          </div>
        ))}
      </div>
    </div>
  )
}

Form İşleme Kalıpları

Doğrulamalı Controlled Form

interface FormData {
  name: string
  description: string
  endDate: string
}

interface FormErrors {
  name?: string
  description?: string
  endDate?: string
}

export function CreateMarketForm() {
  const [formData, setFormData] = useState<FormData>({
    name: '',
    description: '',
    endDate: ''
  })

  const [errors, setErrors] = useState<FormErrors>({})

  const validate = (): boolean => {
    const newErrors: FormErrors = {}

    if (!formData.name.trim()) {
      newErrors.name = 'İsim gereklidir'
    } else if (formData.name.length > 200) {
      newErrors.name = 'İsim 200 karakterden az olmalıdır'
    }

    if (!formData.description.trim()) {
      newErrors.description = 'Açıklama gereklidir'
    }

    if (!formData.endDate) {
      newErrors.endDate = 'Bitiş tarihi gereklidir'
    }

    setErrors(newErrors)
    return Object.keys(newErrors).length === 0
  }

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault()

    if (!validate()) return

    try {
      await createMarket(formData)
      // Başarı işleme
    } catch (error) {
      // Hata işleme
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        value={formData.name}
        onChange={e => setFormData(prev => ({ ...prev, name: e.target.value }))}
        placeholder="Market ismi"
      />
      {errors.name && <span className="error">{errors.name}</span>}

      {/* Diğer alanlar */}

      <button type="submit">Market Oluştur</button>
    </form>
  )
}

Error Boundary Kalıbı

interface ErrorBoundaryState {
  hasError: boolean
  error: Error | null
}

export class ErrorBoundary extends React.Component<
  { children: React.ReactNode },
  ErrorBoundaryState
> {
  state: ErrorBoundaryState = {
    hasError: false,
    error: null
  }

  static getDerivedStateFromError(error: Error): ErrorBoundaryState {
    return { hasError: true, error }
  }

  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    console.error('Error boundary caught:', error, errorInfo)
  }

  render() {
    if (this.state.hasError) {
      return (
        <div className="error-fallback">
          <h2>Bir şeyler yanlış gitti</h2>
          <p>{this.state.error?.message}</p>
          <button onClick={() => this.setState({ hasError: false })}>
            Tekrar dene
          </button>
        </div>
      )
    }

    return this.props.children
  }
}

// Kullanım
<ErrorBoundary>
  <App />
</ErrorBoundary>

Animasyon Kalıpları

Framer Motion Animasyonları

import { motion, AnimatePresence } from 'framer-motion'

// PASS: Liste animasyonları
export function AnimatedMarketList({ markets }: { markets: Market[] }) {
  return (
    <AnimatePresence>
      {markets.map(market => (
        <motion.div
          key={market.id}
          initial={{ opacity: 0, y: 20 }}
          animate={{ opacity: 1, y: 0 }}
          exit={{ opacity: 0, y: -20 }}
          transition={{ duration: 0.3 }}
        >
          <MarketCard market={market} />
        </motion.div>
      ))}
    </AnimatePresence>
  )
}

// PASS: Modal animasyonları
export function Modal({ isOpen, onClose, children }: ModalProps) {
  return (
    <AnimatePresence>
      {isOpen && (
        <>
          <motion.div
            className="modal-overlay"
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            onClick={onClose}
          />
          <motion.div
            className="modal-content"
            initial={{ opacity: 0, scale: 0.9, y: 20 }}
            animate={{ opacity: 1, scale: 1, y: 0 }}
            exit={{ opacity: 0, scale: 0.9, y: 20 }}
          >
            {children}
          </motion.div>
        </>
      )}
    </AnimatePresence>
  )
}

Erişilebilirlik Kalıpları

Klavye Navigasyonu

export function Dropdown({ options, onSelect }: DropdownProps) {
  const [isOpen, setIsOpen] = useState(false)
  const [activeIndex, setActiveIndex] = useState(0)

  const handleKeyDown = (e: React.KeyboardEvent) => {
    switch (e.key) {
      case 'ArrowDown':
        e.preventDefault()
        setActiveIndex(i => Math.min(i + 1, options.length - 1))
        break
      case 'ArrowUp':
        e.preventDefault()
        setActiveIndex(i => Math.max(i - 1, 0))
        break
      case 'Enter':
        e.preventDefault()
        onSelect(options[activeIndex])
        setIsOpen(false)
        break
      case 'Escape':
        setIsOpen(false)
        break
    }
  }

  return (
    <div
      role="combobox"
      aria-expanded={isOpen}
      aria-haspopup="listbox"
      onKeyDown={handleKeyDown}
    >
      {/* Dropdown implementasyonu */}
    </div>
  )
}

Focus Yönetimi

export function Modal({ isOpen, onClose, children }: ModalProps) {
  const modalRef = useRef<HTMLDivElement>(null)
  const previousFocusRef = useRef<HTMLElement | null>(null)

  useEffect(() => {
    if (isOpen) {
      // Şu anki focus'lanmış elementi kaydet
      previousFocusRef.current = document.activeElement as HTMLElement

      // Modal'a focus yap
      modalRef.current?.focus()
    } else {
      // Kapatırken focus'u geri yükle
      previousFocusRef.current?.focus()
    }
  }, [isOpen])

  return isOpen ? (
    <div
      ref={modalRef}
      role="dialog"
      aria-modal="true"
      tabIndex={-1}
      onKeyDown={e => e.key === 'Escape' && onClose()}
    >
      {children}
    </div>
  ) : null
}

Unutmayın: Modern frontend kalıpları sürdürülebilir, performanslı kullanıcı arayüzleri sağlar. Proje karmaşıklığınıza uyan kalıpları seçin.

Source repo
affaan-m/ECC
Skill path
docs/tr/skills/frontend-patterns/SKILL.md
Commit SHA
4e973d3eaf92
Repository license
MIT
Data collected