İçeriğe geç
react

React Props Sistemi: Veri Aktarımının A'dan Z'ye Rehberi

Tarık Tunç
React Props Sistemi: Veri Aktarımının A'dan Z'ye Rehberi

React Props Sistemi: Veri Aktarımının A'dan Z'ye Rehberi

React'te bileşenler arası iletişimin temel mekanizması props (properties) sistemidir. Props, üst bileşenden alt bileşene veri aktarmanın standart yoludur ve React'in tek yönlü veri akışı (unidirectional data flow) felsefesinin temelini oluşturur. Bu yazıda props sisteminin tüm yönlerini, ileri seviye kullanım tekniklerini ve en iyi uygulamaları detaylı olarak ele alacağız.

Props Nedir?

Props, bir bileşene dışarıdan aktarılan, salt okunur (read-only) verilerdir. HTML elementlerinin attribute'ları nasıl çalışıyorsa, React bileşenlerinin props'ları da benzer şekilde çalışır:

// Props aktarma - HTML attribute'larına benzer
function App() {
  return (
    <ProductCard
      name="React Öğrenme Kitabı"
      price={49.99}
      inStock={true}
      tags={['react', 'javascript', 'frontend']}
      onAddToCart={() => console.log('Sepete eklendi')}
    />
  );
}

// Props alma - destructuring ile
function ProductCard({ name, price, inStock, tags, onAddToCart }) {
  return (
    <div className="product-card">
      <h3>{name}</h3>
      <p className="price">{price.toFixed(2)} TL</p>
      <span className={inStock ? 'in-stock' : 'out-of-stock'}>
        {inStock ? 'Stokta' : 'Tükendi'}
      </span>
      <div className="tags">
        {tags.map(tag => (
          <span key={tag} className="tag">#{tag}</span>
        ))}
      </div>
      <button onClick={onAddToCart} disabled={!inStock}>
        Sepete Ekle
      </button>
    </div>
  );
}
Props, bir bileşenin "yapılandırma"sıdır. Tıpkı bir fonksiyonun parametreleri gibi, bileşenin nasıl davranacağını ve ne göstereceğini belirler.

Props Türleri

React props olarak her türlü JavaScript değerini aktarabilirsiniz:

  • String: name="Tarik" veya name={'Tarik'}
  • Number: age={30}
  • Boolean: isActive={true} veya kısaca isActive
  • Array: items={[1, 2, 3]}
  • Object: user={{ name: 'Tarik', age: 30 }}
  • Function: onClick={() => handleClick()}
  • JSX / React Element: icon={<Icon />}
  • null / undefined: Bileşen render etmemek için

Default Props

Bileşenlere varsayılan değerler atamak için JavaScript'in destructuring varsayılan değer sözdizimini kullanabilirsiniz:

function Alert({
  type = 'info',
  message,
  dismissible = true,
  duration = 5000,
  onClose = () => {}
}) {
  const icons = {
    info: 'ℹ️',
    success: '✅',
    warning: '⚠️',
    error: '❌'
  };

  return (
    <div className={`alert alert-${type}`} role="alert">
      <span className="alert-icon">{icons[type]}</span>
      <p className="alert-message">{message}</p>
      {dismissible && (
        <button
          className="alert-close"
          onClick={onClose}
          aria-label="Bildirimi kapat"
        >
          &times;
        </button>
      )}
    </div>
  );
}

// Kullanım - sadece zorunlu prop'u veriyoruz
<Alert message="İşlem başarılı!" />
// type='info', dismissible=true, duration=5000 varsayılanları kullanılır

<Alert type="error" message="Bir hata oluştu" dismissible={false} />

Children Props

React'te children özel bir prop'tur. Bileşenin açılış ve kapanış tag'ları arasına yazılan her şey children olarak aktarılır:

function Card({ title, children, footer }) {
  return (
    <div className="card">
      {title && <div className="card-header"><h3>{title}</h3></div>}
      <div className="card-body">
        {children}
      </div>
      {footer && <div className="card-footer">{footer}</div>}
    </div>
  );
}

// Kullanım
function App() {
  return (
    <Card
      title="Kullanıcı Bilgileri"
      footer={<button>Kaydet</button>}
    >
      <p>Ad: Tarik Tunç</p>
      <p>E-posta: tarik@example.com</p>
      <p>Rol: Geliştirici</p>
    </Card>
  );
}

İpucu: children prop'u sadece metin veya JSX değil, fonksiyon da olabilir. Bu pattern "render props" olarak bilinir ve bileşenler arası mantık paylaşımı için güçlü bir tekniktir.

Props ile Callback Fonksiyonları

Alt bileşenden üst bileşene veri göndermek için callback fonksiyonları props olarak aktarılır. Bu, React'in tek yönlü veri akışını koruyarak çift yönlü iletişim sağlamanın yoludur:

function SearchBar({ onSearch, placeholder = 'Ara...' }) {
  const [query, setQuery] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    if (query.trim()) {
      onSearch(query); // Üst bileşene veri gönderme
    }
  };

  return (
    <form onSubmit={handleSubmit} className="search-bar">
      <input
        type="text"
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder={placeholder}
      />
      <button type="submit">Ara</button>
    </form>
  );
}

function ProductPage() {
  const [results, setResults] = useState([]);

  const handleSearch = async (searchQuery) => {
    const response = await fetch(`/api/products?q=${searchQuery}`);
    const data = await response.json();
    setResults(data);
  };

  return (
    <div>
      <SearchBar onSearch={handleSearch} placeholder="Ürün ara..." />
      <ul>
        {results.map(product => (
          <li key={product.id}>{product.name}</li>
        ))}
      </ul>
    </div>
  );
}

Props Doğrulama: PropTypes

Bileşenlerin beklediği props türlerini doğrulamak için PropTypes kütüphanesini kullanabilirsiniz. TypeScript kullanmıyorsanız bu özellikle önemlidir:

import PropTypes from 'prop-types';

function UserAvatar({ src, alt, size, status }) {
  return (
    <div className={`avatar avatar-${size}`}>
      <img src={src} alt={alt} />
      <span className={`status-dot status-${status}`} />
    </div>
  );
}

UserAvatar.propTypes = {
  src: PropTypes.string.isRequired,
  alt: PropTypes.string.isRequired,
  size: PropTypes.oneOf(['small', 'medium', 'large']),
  status: PropTypes.oneOf(['online', 'offline', 'away'])
};

UserAvatar.defaultProps = {
  size: 'medium',
  status: 'offline'
};

Bilgi: TypeScript kullanıyorsanız PropTypes yerine TypeScript interface/type tanımları tercih edilmelidir. TypeScript, derleme zamanında (compile time) tip kontrolü sağlarken PropTypes yalnızca çalışma zamanında (runtime) kontrol yapar.

Prop Drilling Sorunu

Props'un birçok seviye boyunca aktarılması gereken durumlara prop drilling denir. Bu durum kodun bakımını zorlaştırır:

// Prop drilling sorunu - theme 4 seviye boyunca aktarılıyor
function App() {
  const [theme, setTheme] = useState('light');
  return <Layout theme={theme} />;
}

function Layout({ theme }) {
  return <Sidebar theme={theme} />;
}

function Sidebar({ theme }) {
  return <NavItem theme={theme} />;
}

function NavItem({ theme }) {
  return <span className={`nav-item ${theme}`}>Menü</span>;
}

// Çözüm: useContext kullanarak
const ThemeContext = createContext('light');

function App() {
  const [theme, setTheme] = useState('light');
  return (
    <ThemeContext.Provider value={theme}>
      <Layout />
    </ThemeContext.Provider>
  );
}

function NavItem() {
  const theme = useContext(ThemeContext);
  return <span className={`nav-item ${theme}`}>Menü</span>;
}

Uyarı: Props immutable (değiştirilemez) olmalıdır. Bir bileşen aldığı props'u asla doğrudan değiştirmemelidir. Props'u değiştirmeye çalışmak React'in temel prensiplerini ihlal eder ve öngörülemeyen hatalara yol açar.

Sonuç

Props sistemi, React bileşen mimarisinin temel taşıdır. Veri aktarımı, callback fonksiyonları, children pattern'i ve composition ile güçlü ve esnek arayüzler oluşturabilirsiniz. Props doğrulaması için PropTypes veya TypeScript kullanmayı, prop drilling sorunlarında Context API veya state management çözümlerini değerlendirmeyi ve bileşenlerinizi mümkün olduğunca yeniden kullanılabilir tasarlamayı unutmayın.

Kaynaklar

İlgili Yazılar