JSX Temelleri: JavaScript'te HTML Yazmak
JSX, React'in gücünü ortaya çıkaran sözdizimi uzantısıdır. Bu derste JSX'i derinlemesine öğrenecek, gerçek dünya örnekleriyle pratik yapacaksınız.
1. JSX Nedir ve Neden Kullanılır?
JSX, JavaScript'in bir uzantısıdır ve HTML'e çok benzer bir sözdizimi sağlar. Ancak aslında JavaScript'tir ve kodunuz çalıştığında React.createElement() çağrılarına dönüştürülür.
1function Greeting() {2 return <h1 className="title">Merhaba, Dünya!</h1>;3}
Temiz, okunabilir ve HTML'e çok benzer.
2. JSX Sözdizimi Kuralları
JSX HTML'e benzer, ancak bazı önemli farklılıkları vardır. Bu kuralları bilmek hata yapmaktan kaçınmanızı sağlar.
Temel JSX Kuralları
- Tek Üst Element
- JSX ifadelerinin tek bir kök (root) elementi olmalıdır. Birden fazla element döndürmek için Fragment kullanın veya bir div ile sarmalayın.
- Tüm Etiketler Kapalı
- HTML'de bazı etiketler (img, br, input) kapanış etiketi gerektirmez. JSX'te MUTLAKA kapatılmalı veya self-closing olmalıdır (örn: <img />, <br />).
- className Kullanın
- HTML'de class kullanırken, JSX'te className kullanmalısınız çünkü class JavaScript'te reserved keyword'dür.
- camelCase Attribute'ler
- HTML attribute'leri (onclick, tabindex) JSX'te camelCase olmalıdır (onClick, tabIndex). Tek istisna: data-* ve aria-* attribute'leri kebab-case kalır.
- Inline Style = Obje
- HTML'de style bir string'dir. JSX'te style bir JavaScript objesidir ve CSS property'leri camelCase yazılır.
- JavaScript İfadeleri
- JSX içinde JavaScript ifadeleri süslü parantez içine yazılır. Bu içinde değişken, fonksiyon çağrısı, ternary operator vs. kullanabilirsiniz.
HTML vs JSX: Kritik Farklar
| HTML | JSX | |
|---|---|---|
| Class tanımlama | class="btn primary" | className="btn primary" |
| Event handler | onclick="handleClick()" | onClick={handleClick} |
| Style attribute | style="color: red; font-size: 16px" | style={{ color: "red", fontSize: 16 }} |
| Self-closing tags | <img src="..."> veya <img src="..." /> | <img src="..." /> (zorunlu) |
| For attribute (label) | <label for="username"> | <label htmlFor="username"> |
| Boolean attributes | <input disabled> | <input disabled={true} /> |
| Comments | <!-- HTML yorum --> | {/* JSX yorum */} |
1// ❌ YANLIŞ - Çoklu kök element2function MyComponent() {3 return (4 <h1>Başlık</h1>5 <p>Paragraf</p>6 );7}89// ✅ DOĞRU - Fragment kullanımı10function MyComponent() {11 return (12 <>13 <h1>Başlık</h1>14 <p>Paragraf</p>15 </>16 );17}1819// ✅ DOĞRU - Sarmalayıcı div20function MyComponent() {21 return (22 <div>23 <h1>Başlık</h1>24 <p>Paragraf</p>25 </div>26 );27}
3. JSX İçinde JavaScript İfadeleri
JSX'in en güçlü özelliği, JavaScript ifadelerini doğrudan markup içinde kullanabilmenizdir. Süslü parantez içinde neredeyse her JavaScript ifadesi çalışır.
3.1 Değişkenleri Kullanma
1function UserCard() {2 const name = 'Ayşe Yılmaz';3 const age = 28;4 const profilePic = '/images/ayse.jpg';56 return (7 <div className="user-card">8 <img src={profilePic} alt={`${name} profil fotoğrafı`} />9 <h2>{name}</h2>10 <p>Yaş: {age}</p>11 </div>12 );13}
3.2 İfadeler ve Hesaplamalar
1function ShoppingCart() {2 const items = [3 { name: 'Laptop', price: 15000, qty: 1 },4 { name: 'Mouse', price: 200, qty: 2 },5 ];67 const total = items.reduce(8 (sum, item) => sum + item.price * item.qty, 09 );1011 return (12 <div>13 <h2>Sepet ({items.length} ürün)</h2>14 <p>Toplam: {total} TL</p>15 <p>KDV Dahil: {(total * 1.18).toFixed(2)} TL</p>16 </div>17 );18}
Süslü parantez içinde sadece ifadeler (expressions) kullanılabilir:
- ✅ Değişkenler:
{name} - ✅ Aritmetik:
{2 + 2} - ✅ Fonksiyon çağrısı:
{getName()} - ✅ Ternary:
{isActive ? 'Aktif' : 'Pasif'} - ❌ if/else:
{if (x) ... }(çalışmaz!) - ❌ for loop:
{for ... }(çalışmaz!)
3.3 Fonksiyon Çağrıları
1function DateDisplay() {2 function formatDate(date: Date): string {3 return date.toLocaleDateString('tr-TR', {4 weekday: 'long', year: 'numeric', month: 'long', day: 'numeric'5 });6 }78 return (9 <div>10 <p>Bugün: {formatDate(new Date())}</p>11 <p>Tarih formatı: {new Date().toISOString()}</p>12 <p>Unix timestamp: {Date.now()}</p>13 </div>14 );15}
4. Koşullu Rendering (Conditional Rendering)
React'te koşula göre farklı UI render etmek çok yaygındır. JSX içinde if/else kullanamayacağınız için JavaScript'in koşullu ifadelerini kullanırsınız.
4.1 Ternary Operator (? :)
1function LoginButton({ isLoggedIn }: { isLoggedIn: boolean }) {2 return (3 <div>4 {isLoggedIn ? (5 <button>Çıkış Yap</button>6 ) : (7 <button>Giriş Yap</button>8 )}9 </div>10 );11}
4.2 Logical AND (&&)
Bir koşul true ise element göster, false ise hiçbir şey gösterme senaryoları için ideal.
1function Notification({ hasNotifications, count }: { hasNotifications: boolean; count: number }) {2 return (3 <div>4 <h2>Bildirimler</h2>5 {hasNotifications && (6 <span className="badge">{count} yeni bildirim</span>7 )}8 </div>9 );10}
&& operatörü ile 0 veya "" kullanırken dikkatli olun:
1// ❌ SORUN - count=0 olduğunda "0" yazısı görünür2{count && <span>{count} ürün</span>}34// ✅ ÇÖZÜM - Boolean dönüşümü yapın5{count > 0 && <span>{count} ürün</span>}6{Boolean(count) && <span>{count} ürün</span>}
4.3 Değişkene Atama Yöntemi
1function WelcomeMessage({ role }: { role: 'admin' | 'user' | 'guest' }) {2 let message;34 if (role === 'admin') {5 message = <h1>Admin Paneline Hoş Geldiniz</h1>;6 } else if (role === 'user') {7 message = <h1>Kullanıcı Sayfasına Hoş Geldiniz</h1>;8 } else {9 message = <h1>Misafir olarak giriş yaptınız</h1>;10 }1112 return (13 <div>{message}</div>14 );15}
4.4 Switch/Case Alternatifi: Object Mapping
1function StatusBadge({ status }: { status: 'success' | 'error' | 'warning' | 'info' }) {2 const statusConfig = {3 success: { text: 'Başarılı', color: 'green' },4 error: { text: 'Hata', color: 'red' },5 warning: { text: 'Uyarı', color: 'yellow' },6 info: { text: 'Bilgi', color: 'blue' }7 };89 const config = statusConfig[status];1011 return (12 <span className={`badge bg-${config.color}`}>13 {config.text}14 </span>15 );16}
5. Listeleri Render Etme ve Key Prop
Dinamik veri listelerini render etmek React'te çok yaygındır. JavaScript'inmap() fonksiyonu bu iş için mükemmeldir.
5.1 Basit Liste
1function FruitList() {2 const fruits = ['Elma', 'Muz', 'Portakal', 'Çilek', 'Karpuz'];34 return (5 <ul>6 {fruits.map((fruit, index) => (7 <li key={index}>{fruit}</li>8 ))}9 </ul>10 );11}
5.2 Obje Listesi
1interface Product {2 id: string;3 name: string;4 price: number;5}67function ProductList({ products }: { products: Product[] }) {8 return (9 <div className="grid gap-4">10 {products.map((product) => (11 <div key={product.id} className="card">12 <h3>{product.name}</h3>13 <p className="price">{product.price} TL</p>14 <button>Sepete Ekle</button>15 </div>16 ))}17 </div>18 );19}
Liste render ederken her zaman benzersiz bir key prop kullanmalısınız:
- ✅ İyi: Benzersiz ID kullanın (
key={item.id}) - ⚠️ Kabul Edilebilir: Index kullanın, ancak sadece liste statikse ve yeniden sıralanmıyorsa
- ❌ Kötü: Key kullanmamak (React uyarısı verir)
- ❌ Kötü: Her render'da değişen bir değer (Math.random() gibi)
Neden önemli? React, key'leri kullanarak hangi öğelerin değiştiğini, eklendiğini veya silindiğini anlar. Yanlış key kullanımı performans sorunlarına ve hatalı render'lara neden olabilir.
5.3 Filtreleme ve Koşullu Liste
1interface Task {2 id: string;3 title: string;4 completed: boolean;5}67function TaskList({ tasks }: { tasks: Task[] }) {8 // Sadece tamamlanmamış görevleri filtrele9 const pendingTasks = tasks.filter(task => !task.completed);1011 // Boş liste kontrolü12 if (pendingTasks.length === 0) {13 return <p>Tüm görevler tamamlandı! 🎉</p>;14 }1516 return (17 <ul>18 {pendingTasks.map(task => (19 <li key={task.id}>{task.title}</li>20 ))}21 </ul>22 );23}
6. React Fragments: Gereksiz div'lerden Kurtulun
JSX'te birden fazla element döndürmek için bir parent element gerekir. Ancak bazen gereksiz div wrapper'ları DOM'u karmaşıklaştırır. Fragment bu sorunu çözer.
Fragment Kullanımı
| Uzun Syntax | Kısa Syntax | |
|---|---|---|
| Syntax | <React.Fragment>...</React.Fragment> | <>...</> |
| Avantaj | Key prop alabilir | Kısa ve temiz |
| Dezavantaj | Daha uzun kod | Key prop alamaz |
| Kullanım senaryosu | Liste içinde fragment kullanımı | Genel kullanım |
1function TableRows() {2 const data = [3 { id: 1, name: 'Ahmet', age: 25 },4 { id: 2, name: 'Mehmet', age: 30 }5 ];67 return (8 <>9 {data.map(person => (10 // Fragment ile key kullanımı11 <React.Fragment key={person.id}>12 <tr>13 <td>{person.name}</td>14 <td>{person.age}</td>15 </tr>16 <tr>17 <td colSpan={2}>Detay bilgiler...</td>18 </tr>19 </React.Fragment>20 ))}21 </>22 );23}
7. Olay Yönetimi (Event Handling)
JSX'te event handler'lar camelCase yazılır ve fonksiyon referansı olarak verilir (string olarak değil).
7.1 Temel Event Handler
1function ClickButton() {2 function handleClick() {3 alert('Butona tıklandı!');4 }56 return (7 <button onClick={handleClick}>Tıkla</button>8 );9}
1// ❌ YANLIŞ - Fonksiyon hemen çalışır2<button onClick={handleClick()}>Tıkla</button>34// ✅ DOĞRU - Fonksiyon referansı verilir5<button onClick={handleClick}>Tıkla</button>67// ✅ DOĞRU - Arrow function ile sarmalama (parametre gerekiyorsa)8<button onClick={() => handleClick('parametre')}>Tıkla</button>
7.2 Event Objesini Kullanma
1function SearchInput() {2 function handleChange(event: React.ChangeEvent<HTMLInputElement>) {3 const value = event.target.value;4 console.log('Arama:', value);5 }67 return (8 <input type="text" onChange={handleChange} placeholder="Ara..." />9 );10}
7.3 Form Submission
1function LoginForm() {2 function handleSubmit(event: React.FormEvent<HTMLFormElement>) {3 event.preventDefault(); // Sayfa yenilenmesini engelle45 const formData = new FormData(event.currentTarget);6 const email = formData.get('email');7 console.log('Giriş:', email);8 }910 return (11 <form onSubmit={handleSubmit}>12 <input name="email" type="email" required />13 <input name="password" type="password" required />14 <button type="submit">Giriş Yap</button>15 </form>16 );17}
8. Props ve Children Pattern
8.1 Props ile Veri Aktarımı
1interface UserProfileProps {2 name: string;3 age: number;4 avatar?: string; // Opsiyonel5}67function UserProfile({ name, age, avatar = '/default-avatar.png' }: UserProfileProps) {8 return (9 <div className="profile">10 <img src={avatar} alt={name} />11 <h2>{name}</h2>12 <p>{age} yaşında</p>13 </div>14 );15}1617// Kullanım18<UserProfile name="Ayşe" age={25} />19<UserProfile name="Mehmet" age={30} avatar="/mehmet.jpg" />
8.2 Children Prop
1interface CardProps {2 title: string;3 children: React.ReactNode;4}56function Card({ title, children }: CardProps) {7 return (8 <div className="card">9 <h3>{title}</h3>10 <div className="card-body">{children}</div>11 </div>12 );13}1415// Kullanım16<Card title="Kullanıcı Bilgileri">17 <p>Ayşe Yılmaz</p>18 <p>Frontend Developer</p>19 <button>Profil</button>20</Card>
8.3 Spread Props
1function Input(props: React.InputHTMLAttributes<HTMLInputElement>) {2 return (3 <input4 className="custom-input"5 {...props}6 />7 );8}910// Kullanım - tüm HTML input attribute'lerini destekler11<Input type="email" placeholder="E-posta" required />12<Input type="password" minLength={8} />
9. JSX'te Styling
9.1 Inline Styles
1function StyledBox() {2 const boxStyle = {3 backgroundColor: '#3b82f6',4 color: 'white',5 padding: '1rem',6 borderRadius: '0.5rem'7 };89 return (10 <div style={boxStyle}>11 Styled Box12 </div>13 );14}
- CSS property'leri camelCase yazılır:
backgroundColor,fontSize - Değerler string veya number:
{{ width: '100px' }}veya{{ width: 100 }} - Number değerler otomatik px olur (width, height vs.):
{{ width: 100 }}→ "100px" - Çift süslü parantez:
style={{ ... }}(dış JSX ifadesi, iç JavaScript objesi)
9.2 className ile CSS
1function Button({ variant = 'primary' }: { variant?: 'primary' | 'secondary' }) {2 const baseClass = 'btn';3 const variantClass = variant === 'primary' ? 'btn-primary' : 'btn-secondary';45 return (6 <button className={`${baseClass} ${variantClass}`}>7 Tıkla8 </button>9 );10}
9.3 Conditional Classes (cn helper)
1import { cn } from '@/lib/utils'; // Tailwind + clsx helper23function Alert({ type, children }: { type: 'info' | 'error'; children: React.ReactNode }) {4 return (5 <div6 className={cn(7 'p-4 rounded-lg', // Base classes8 type === 'info' && 'bg-blue-100 text-blue-900',9 type === 'error' && 'bg-red-100 text-red-900'10 )}11 >12 {children}13 </div>14 );15}
10. JSX Best Practices
JSX Yazımında En İyi Pratikler
Bileşenleri Küçük Tutun
Her bileşen tek bir şey yapmalı. Çok büyük bileşenleri daha küçük, yeniden kullanılabilir parçalara bölün.
1// ✅ İyi2function ProductCard({ product }) {3 return (4 <div>5 <ProductImage src={product.image} />6 <ProductInfo name={product.name} price={product.price} />7 <AddToCartButton productId={product.id} />8 </div>9 );10}
Prop Destructuring Kullanın
Props'u destructure ederek daha temiz kod yazın.
1// ❌ Kötü2function User(props) {3 return <h1>{props.name}</h1>;4}56// ✅ İyi7function User({ name }) {8 return <h1>{name}</h1>;9}
Key Prop'u Doğru Kullanın
Liste render ederken her zaman benzersiz, stabil key kullanın.
1// ❌ Kötü - index2{items.map((item, i) => <div key={i}>...</div>)}34// ❌ Kötü - random5{items.map(item => <div key={Math.random()}>...</div>)}67// ✅ İyi - benzersiz ID8{items.map(item => <div key={item.id}>...</div>)}
Event Handler İsimlendirme
Event handler'ları handle ile başlatın.
1function Form() {2 const handleSubmit = () => { ... };3 const handleChange = () => { ... };4 const handleCancel = () => { ... };56 return <form onSubmit={handleSubmit}>...</form>;7}
Koşulları Erken Return ile Basitleştirin
Karmaşık koşullu rendering yerine early return kullanın.
1function UserList({ users }) {2 // Early return ile boş durum kontrolü3 if (!users || users.length === 0) {4 return <p>Kullanıcı bulunamadı</p>;5 }67 return (8 <ul>9 {users.map(user => <li key={user.id}>{user.name}</li>)}10 </ul>11 );12}
11. Yaygın JSX Hataları ve Çözümleri
12. Özet ve Sırada Ne Var?
Bu derste şunları öğrendiniz:
- ✅ JSX'in ne olduğu ve JavaScript'e nasıl dönüştüğü
- ✅ JSX sözdizimi kuralları ve HTML'den farkları
- ✅ JavaScript ifadelerini JSX içinde kullanma
- ✅ Koşullu rendering teknikleri (ternary, &&, if/else)
- ✅ Liste rendering ve key prop'unun önemi
- ✅ Fragment kullanımı ve gereksiz wrapper'lardan kurtulma
- ✅ Event handling ve form yönetimi
- ✅ Props, children ve composition pattern'leri
- ✅ JSX'te styling (inline, className)
- ✅ Best practices ve yaygın hatalardan kaçınma
Sırada Ne Var?
Bir sonraki derste React State ve Hooks konusuna dalacağız. Bileşenlerinizin interaktif hale gelmesi için state yönetimini öğreneceksiniz.
- 🎯 useState hook ile state yönetimi
- 🎯 Event handler'lar ile state güncelleme
- 🎯 Controlled vs Uncontrolled components
- 🎯 State lifting ve component iletişimi
JSX öğrenmenin en iyi yolu pratik yapmaktır. Şimdi kendi bileşenlerinizi oluşturmayı deneyin:
- 📝 Bir kullanıcı profil kartı bileşeni yapın
- 📝 Liste filtreleme özelliği ekleyin
- 📝 Koşullu rendering ile farklı UI durumları gösterin
- 📝 Form component'i oluşturun