Takip et

Eski React Kodunu Anlamak: “Classy Weather” Uygulamasını Geliştirmenin Öğrettikleri

React, modern web geliştirmenin temel taşlarından biri haline geldi. Ancak, teknolojinin hızlı evrimiyle birlikte, birkaç yıl önce yazılmış bir Re…

Eski React Kodunu Anlamak: “Classy Weather” Uygulamasını Geliştirmenin Öğrettikleri

React, modern web geliştirmenin temel taşlarından biri haline geldi. Ancak, teknolojinin hızlı evrimiyle birlikte, birkaç yıl önce yazılmış bir React projesi ile bugün yazılan bir proje arasında önemli farklılıklar görmek mümkün. Özellikle React Hooks’un hayatımıza girmesinden önce yazılmış, “sınıf bileşenleri” (class components) ağırlıklı kod tabanları, yeni nesil geliştiriciler için kafa karıştırıcı olabilir. Bu makalede, eski React paradigmalarını anlamanın önemini, basit bir hava durumu uygulaması olan “Classy Weather” projesini sınıf bileşenleriyle geliştirme deneyimim üzerinden ele alacağız. Bu yolculuk, hem geçmişi anlamanıza hem de modern React’ın değerini daha iyi kavramanıza yardımcı olacak.

Neden Eski React Kodunu Anlamak Önemli?

Günümüzün React ekosistemi büyük ölçüde fonksiyonel bileşenler ve Hooks etrafında dönse de, dünya genelinde milyonlarca satır eski React kodu aktif olarak kullanılmaya devam ediyor. Büyük ölçekli kurumsal uygulamalar, mirasa dayalı projeler veya uzun süredir bakımı yapılan sistemler genellikle sınıf bileşenleri üzerine inşa edilmiştir. Bu kod tabanlarını anlamak, sürdürmek, hata ayıklamak veya modern yapılara geçiş yapmak isteyen her geliştirici için kritik bir beceridir. “Classy Weather” gibi basit bir proje üzerinden bu eski yapıları öğrenmek, gerçek dünya senaryolarına hazırlık niteliğindedir.

Mevcut Projelerin Bakımı ve Geliştirilmesi

Birçok şirketin hala sınıf bileşenleri içeren aktif projeleri bulunmaktadır. Yeni bir ekibe katıldığınızda veya mevcut bir projeyi devraldığınızda, bu kod tabanlarını okuyabilmek ve üzerinde çalışabilmek işinizin temel bir parçası olacaktır. Eski React kodu bilgisi, bu projelerde etkin bir şekilde katkıda bulunmanızı sağlar.

Geçiş Süreçlerini Yönetmek

Eski projeleri Hooks’a geçirme kararı alındığında, mevcut yapıyı derinlemesine anlamak, geçişin daha sorunsuz ve hatasız olmasını sağlar. Hangi sınıf bileşeni metodunun hangi Hook’a karşılık geldiğini bilmek, bu süreçte size büyük avantaj kazandırır.

React’ın Evrimini Kavramak

React’ın sınıf bileşenlerinden fonksiyonel bileşenlere ve Hooks’a geçişi, kütüphanenin felsefesini ve gelişim yönünü gösteren önemli bir dönüm noktasıdır. Bu evrimi anlamak, React’ın neden belirli tasarım kararları aldığını ve gelecekteki olası yönelimlerini daha iyi kavramanıza yardımcı olur.

Classy Weather Projesi: Bir Zaman Makinesi Yolculuğu

“Classy Weather” projesi, basit bir hava durumu uygulamasıdır. Kullanıcının konumuna göre veya arama çubuğuna girilen şehre göre hava durumu bilgilerini (sıcaklık, nem, rüzgar hızı vb.) gösterir. Bu projeyi sınıf bileşenleri kullanarak sıfırdan inşa etmek, eski React kodunun nasıl çalıştığına dair pratik bir bakış açısı sunar. Bu süreçte, veri çekme, durumu yönetme ve bileşenler arası iletişimi sınıf bileşenleri ile nasıl sağladığımızı deneyimleyeceğiz.

Proje Yapısı ve İlk Bileşen

Classy Weather projesinin temelinde, her biri bir sınıf olarak tanımlanmış bileşenler bulunur. Örneğin, ana uygulama bileşenimiz şöyle görünebilir:


import React from 'react';
import WeatherDisplay from './WeatherDisplay';
import SearchBar from './SearchBar';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      weatherData: null,
      location: 'Istanbul',
      error: null,
      loading: false,
    };
    this.handleSearch = this.handleSearch.bind(this);
  }

  handleSearch(city) {
    this.setState({ location: city }, () => {
      this.fetchWeatherData();
    });
  }

  fetchWeatherData() {
    // API çağrısı burada yapılacak
  }

  render() {
    return (
      

Classy Weather

{this.state.loading &&

Yükleniyor...

} {this.state.error &&

Hata: {this.state.error}

} {this.state.weatherData && }
); } } export default App;

Durum Yönetimi: this.state ve setState()

Sınıf bileşenlerinde durum (state), this.state objesi içinde tutulur. Durumu güncellemek için this.setState() metodu kullanılır. Bu metodun asenkron çalıştığını ve doğrudan this.state'i değiştirmemeniz gerektiğini unutmamak önemlidir. Yukarıdaki örnekte handleSearch metodu, location durumunu günceller ve bir geri çağrı (callback) ile hava durumu verisini çeker.

Yaşam Döngüsü Metotları

Sınıf bileşenlerinin en belirgin özelliklerinden biri, bileşenin farklı yaşam döngüsü evrelerinde çalışan özel metotlara sahip olmasıdır. Classy Weather uygulamasında en sık kullanılanlar şunlardır:

  • componentDidMount(): Bileşen DOM'a ilk kez bağlandığında çalışır. Genellikle ilk veri çekme işlemleri burada yapılır.
  • componentDidUpdate(prevProps, prevState): Bileşen güncellendiğinde (props veya state değiştiğinde) çalışır. Önceki props ve state değerlerine erişim sağlar. Durum değişimlerine tepki vermek için idealdir.
  • componentWillUnmount(): Bileşen DOM'dan kaldırılmadan hemen önce çalışır. Bellek sızıntılarını önlemek için temizlik işlemleri (abonelikleri iptal etme, zamanlayıcıları temizleme) burada yapılır.

Sınıf Bileşenlerinin Temelleri: State ve Lifecycle

Sınıf bileşenlerinin kalbi, state yönetimi ve lifecycle metotlarıdır. Bu iki kavram, bileşenin davranışını ve DOM ile etkileşimini belirler.

this.state ve setState'in Derinlikleri

this.state, bir bileşenin iç durumunu tutan düz bir JavaScript objesidir. setState() ise bu durumu güvenli bir şekilde güncellemek için kullanılan tek yoldur. setState()'in iki farklı kullanım şekli vardır:

  1. Obje olarak güncelleme: this.setState({ key: 'yeni değer' })
  2. Fonksiyon olarak güncelleme: Özellikle önceki duruma bağımlı güncellemelerde kullanılır.
    
    this.setState((prevState) => ({
      sayac: prevState.sayac + 1
    }));
        

setState()'in asenkron doğası, birçok yeni geliştiriciyi şaşırtır. Güncelleme sonrası bir işlem yapmak istiyorsanız, ikinci parametre olarak bir geri çağrı fonksiyonu geçmelisiniz (yukarıdaki handleSearch örneğinde olduğu gibi).

Yaşam Döngüsü Metotları: Bileşenin Hayat Hikayesi

Bir React bileşeninin hayatı, çeşitli evrelerden geçer. Bu evrelerin her birinde belirli metotlar otomatik olarak çağrılır:

  • Mounting (Bağlama): Bileşenin ilk kez oluşturulup DOM'a eklenmesi.
    • constructor()
    • static getDerivedStateFromProps()
    • render()
    • componentDidMount()
  • Updating (Güncelleme): Bileşenin props veya state değiştiğinde yeniden render edilmesi.
    • static getDerivedStateFromProps()
    • shouldComponentUpdate() (performans optimizasyonu için)
    • render()
    • getSnapshotBeforeUpdate()
    • componentDidUpdate()
  • Unmounting (Kaldırma): Bileşenin DOM'dan kaldırılması.
    • componentWillUnmount()

Classy Weather uygulamasında, hava durumu verisini ilk kez çekerken componentDidMount, şehir değiştiğinde ise componentDidUpdate kullanırız:


// App.js içinde
componentDidMount() {
  this.fetchWeatherData(); // Uygulama yüklendiğinde ilk veriyi çek
}

componentDidUpdate(prevProps, prevState) {
  if (prevState.location !== this.state.location) {
    this.fetchWeatherData(); // Şehir değiştiğinde yeni veriyi çek
  }
}

Prop Drilling ve Context API'nin İlk Adımları

Eski React projelerinde, veriyi üst bileşenlerden alt bileşenlere aktarmak için genellikle "prop drilling" adı verilen bir yöntem kullanılırdı. Bu, verinin birçok ara bileşen üzerinden prop olarak manuel olarak geçirilmesi anlamına geliyordu. Derin bir bileşen ağacında bu durum, kodu okunaksız ve bakımı zor hale getirebilirdi.

Prop Drilling'in Zorlukları

Classy Weather uygulamasında, ana App bileşeninden WeatherDisplay bileşenine hava durumu verisini geçirmek kolaydır. Ancak, eğer WeatherDisplay'in içinde başka alt bileşenler olsaydı ve bu alt bileşenlerin de bu verilere ihtiyacı olsaydı, prop drilling kaçınılmaz hale gelirdi.


// Örnek bir prop drilling senaryosu

  
    
      
    
  

Burada data prop'u, ParentComponent ve ChildComponent tarafından doğrudan kullanılmasa bile, GrandchildComponent'e ulaşmak için aradan geçmek zorunda kalıyor.

React Context API ile Çözümler

Prop drilling sorununu çözmek için React, Context API'yi tanıttı. Context, belirli bir veri türünü bileşen ağacının derinliklerinde, prop geçişine gerek kalmadan paylaşmanın bir yoludur. Classy Weather uygulamasında, örneğin tema ayarlarını (açık/koyu mod) veya API anahtarını global olarak paylaşmak için kullanılabilirdi.


// Tema Context'i oluşturma
const ThemeContext = React.createContext('light');

class App extends React.Component {
  state = { theme: 'dark' }; // Tema durumunu App bileşeninde tut

  render() {
    return (
      
        
      
    );
  }
}

class Toolbar extends React.Component {
  render() {
    return (
      
    );
  }
}

class ThemedButton extends React.Component {
  // Context'i tüketme
  static contextType = ThemeContext;

  render() {
    return ;
  }
}

Bu örnekte, ThemedButton bileşeni, App bileşeninden gelen theme değerine doğrudan this.context üzerinden erişebilir, aradaki Toolbar bileşenine prop geçişi yapmaya gerek kalmaz.

Higher-Order Components (HOCs) ve Render Props: Yeniden Kullanım Desenleri

Sınıf bileşenleri döneminde, kod tekrarını azaltmak ve bileşen mantığını yeniden kullanmak için iki ana desen öne çıkıyordu: Higher-Order Components (HOCs) ve Render Props.

Higher-Order Components (HOCs)

HOC, bir bileşen alan ve yeni bir bileşen döndüren bir fonksiyondur. Genellikle veri çekme, yetkilendirme veya stil gibi ortak mantığı paylaşmak için kullanılırlar. Örneğin, Classy Weather uygulamasında API'den veri çeken bir HOC oluşturulabilirdi:


function withWeatherData(WrappedComponent, defaultCity = 'Ankara') {
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        data: null,
        loading: true,
        error: null,
        city: defaultCity,
      };
    }

    componentDidMount() {
      this.fetchData(this.state.city);
    }

    componentDidUpdate(prevProps, prevState) {
      if (prevState.city !== this.state.city) {
        this.fetchData(this.state.city);
      }
    }

    fetchData = async (city) => {
      this.setState({ loading: true, error: null });
      try {
        // API çağrısı
        const response = await fetch(https://api.weatherapi.com/v1/current.json?key=YOUR_API_KEY&q=${city});
        const data = await response.json();
        this.setState({ data, loading: false });
      } catch (error) {
        this.setState({ error: error.message, loading: false });
      }
    };

    render() {
      return (
         this.setState({ city })}
        />
      );
    }
  };
}

// Kullanım:
class MyWeatherComponent extends React.Component {
  render() {
    const { weatherData, weatherLoading, weatherError, setCity } = this.props;
    // Hava durumu verisini göster
    return (
      
setCity(e.target.value)} placeholder="Şehir girin" /> {weatherLoading &&

Yükleniyor...

} {weatherError &&

Hata: {weatherError}

} {weatherData &&

Sıcaklık: {weatherData.current.temp_c}°C

}
); } } export default withWeatherData(MyWeatherComponent);

Bu HOC, MyWeatherComponent'e hava durumu verilerini ve ilgili durumları prop olarak enjekte eder. Bu sayede MyWeatherComponent sadece veriyi gösterme işine odaklanabilir.

Render Props

Render Props deseni, bir bileşenin ne render edeceğini bir prop aracılığıyla, genellikle bir fonksiyon olarak, dinamik olarak belirlemesine olanak tanır. Bu, HOC'lara bir alternatif olarak düşünülebilir ve daha esnek bir bileşen kompozisyonu sağlar.


class WeatherDataProvider extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: null,
      loading: true,
      error: null,
      city: props.defaultCity || 'Ankara',
    };
  }

  componentDidMount() {
    this.fetchData(this.state.city);
  }

  componentDidUpdate(prevProps, prevState) {
    if (prevState.city !== this.state.city) {
      this.fetchData(this.state.city);
    }
  }

  fetchData = async (city) => { /* ... (HOC örneğindeki fetch kodu) ... */ };
  setCity = (city) => this.setState({ city });

  render() {
    return this.props.children({
      weatherData: this.state.data,
      weatherLoading: this.state.loading,
      weatherError: this.state.error,
      setCity: this.setCity,
    });
  }
}

// Kullanım:
class MyWeatherComponent extends React.Component {
  render() {
    return (
      
        {({ weatherData, weatherLoading, weatherError, setCity }) => (
          
setCity(e.target.value)} placeholder="Şehir girin" /> {weatherLoading &&

Yükleniyor...

} {weatherError &&

Hata: {weatherError}

} {weatherData &&

Sıcaklık: {weatherData.current.temp_c}°C

}
)} ); } }

Render Props deseni, mantığı bir bileşenden diğerine "geçirme" konusunda HOC'lardan daha açık ve esnek bir yol sunar, çünkü mantık doğrudan JSX içinde bir fonksiyon olarak tanımlanır.

Eski React Kodunda Hata Ayıklama ve Optimizasyon

Eski React kod tabanlarında çalışırken hata ayıklama ve performans optimizasyonu, modern React'a göre farklı yaklaşımlar gerektirebilir.

Hata Ayıklama Stratejileri

Sınıf bileşenlerinde hata ayıklarken:

  • React Developer Tools: Tarayıcı eklentisi, bileşen ağacını, prop'ları ve state'i incelemek için vazgeçilmezdir. Özellikle this.state ve this.props değerlerini anlık olarak görmek çok faydalıdır.
  • console.log(): Yaşam döngüsü metotlarının içine console.log() ekleyerek hangi evrenin ne zaman tetiklendiğini ve state/props değerlerinin nasıl değiştiğini takip edebilirsiniz.
  • Hata Sınırları (Error Boundaries): Uygulamanın bir kısmındaki hataların tüm uygulamayı çökertmesini önlemek için sınıf bileşenleri kullanılarak hata sınırları oluşturulabilir.
    
    class ErrorBoundary extends React.Component {
      constructor(props) {
        super(props);
        this.state = { hasError: false };
      }
    
      static getDerivedStateFromError(error) {
        return { hasError: true };
      }
    
      componentDidCatch(error, errorInfo) {
        console.error("Hata yakalandı:", error, errorInfo);
      }
    
      render() {
        if (this.state.hasError) {
          return 

    Bir şeyler ters gitti.

    ; } return this.props.children; } }

Performans Optimizasyonları

Sınıf bileşenlerinde performansı artırmak için:

  • shouldComponentUpdate(): Bu yaşam döngüsü metodu, bileşenin gereksiz yere yeniden render edilmesini engellemek için kullanılabilir. true dönerse bileşen render edilir, false dönerse edilmez.
    
    class MyOptimizedComponent extends React.Component {
      shouldComponentUpdate(nextProps, nextState) {
        return nextProps.value !== this.props.value || nextState.count !== this.state.count;
      }
      // ...
    }
        

  • React.PureComponent: shouldComponentUpdate metodunu props ve state'in yüzeysel karşılaştırmasını yaparak otomatik olarak uygulayan bir temel sınıftır. Karmaşık obje veya dizi prop'ları için dikkatli kullanılmalıdır.
  • Memoization: reselect gibi kütüphanelerle türetilmiş verileri önbelleğe alarak gereksiz hesaplamaları önleyebilirsiniz.

Geçiş ve Modern React ile Karşılaştırma

Eski React kodunu anlamak, modern React'ın sunduğu kolaylıkları ve avantajları daha iyi kavramamızı sağlar. Hooks, sınıf bileşenlerinin karmaşıklığını basitleştirerek aynı işlevselliği daha az ve daha okunabilir kodla yapmamızı sağlar.

Sınıf Bileşenlerinden Hooks'a

Classy Weather projesindeki App bileşenini Hooks ile yeniden yazsaydık, useState ve useEffect gibi Hook'ları kullanırdık:


import React, { useState, useEffect } from 'react';
import WeatherDisplay from './WeatherDisplay';
import SearchBar from './SearchBar';

function App() {
  const [weatherData, setWeatherData] = useState(null);
  const [location, setLocation] = useState('Istanbul');
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const fetchWeatherData = async () => {
      setLoading(true);
      setError(null);
      try {
        const response = await fetch(https://api.weatherapi.com/v1/current.json?key=YOUR_API_KEY&q=${location});
        if (!response.ok) {
          throw new Error('Hava durumu verisi çekilemedi.');
        }
        const data = await response.json();
        setWeatherData(data);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchWeatherData();
  }, [location]); // location değiştiğinde tekrar çalışır

  const handleSearch = (city) => {
    setLocation(city);
  };

  return (
    

Classy Weather (Hooks)

{loading &&

Yükleniyor...

} {error &&

Hata: {error}

} {weatherData && }
); } export default App;

Görüldüğü gibi, useState ile durum yönetimi basitleşirken, useEffect ile componentDidMount, componentDidUpdate ve componentWillUnmount'ın işlevleri tek bir yerde toplanmıştır. Bağımlılık dizisi [location], location değiştiğinde useEffect'in tekrar çalışmasını sağlar, bu da componentDidUpdate'teki koşullu kontrole benzer bir işlev görür.

Farklılıklar ve Avantajlar

Aşağıdaki tablo, sınıf bileşenleri ve Hooks arasındaki temel farkları özetlemektedir:

Özellik Sınıf Bileşenleri Fonksiyonel Bileşenler (Hooks ile)
Durum Yönetimi this.state, this.setState() useState()
Yaşam Döngüsü componentDidMount(), componentDidUpdate(), vb. useEffect()
this Bağlamı Gereklidir, bağlama (binding) sorunları olabilir. Gerekli değil, fonksiyonel yapı.
Mantık Paylaşımı HOCs, Render Props Özel Hook'lar (Custom Hooks)
Kod Uzunluğu Genellikle daha uzun ve daha karmaşık. Daha kısa ve daha okunabilir.
Öğrenme Eğrisi this ve yaşam döngüsü metotları nedeniyle daha dik olabilir. Daha düz, JavaScript fonksiyonlarına yakın.

Sonuç: Eskiye Saygı, Geleceğe Hazırlık

"Classy Weather" uygulamasını sınıf bileşenleriyle geliştirmek, eski React kod tabanlarının nasıl çalıştığına dair paha biçilmez bir bakış açısı sunuyor. this.state'ten yaşam döngüsü metotlarına, prop drilling'den HOC'lara kadar birçok eski deseni deneyimlemek, modern React'ın neden bu kadar popüler olduğunu ve Hooks'un ne kadar büyük bir kolaylık getirdiğini daha iyi anlamamızı sağlıyor. Eski kodu anlamak, sadece geçmişe saygı duymakla kalmaz, aynı zamanda mevcut projelerde etkin bir şekilde çalışmanızı ve gelecekteki geçiş süreçlerini daha bilinçli yönetmenizi sağlar. React ekosisteminin sürekli evrim geçirdiğini unutmayın; hem eskiyi bilmek hem de yeniyi takip etmek, sizi daha yetkin ve çok yönlü bir geliştirici yapacaktır.

SSS (Sık Sorulan Sorular)

1. Neden hala sınıf bileşenleri öğrenmeliyim?

Milyonlarca satır eski React kodu hala aktif olarak kullanılıyor ve bakımı yapılıyor. Bu kod tabanlarını anlayabilmek, mevcut projelerde çalışmak, hata ayıklamak veya modern yapılara geçiş yapmak için kritik bir beceridir. Ayrıca, React'ın evrimini ve Hooks'un neden ortaya çıktığını daha iyi anlamanıza yardımcı olur.

2. Sınıf bileşenlerinde this.setState() neden asenkrondur?

setState()'in asenkron olması, React'ın performans optimizasyonları yapmasına olanak tanır. Birden fazla setState() çağrısını tek bir render döngüsünde birleştirerek (batching) gereksiz yeniden render'ları önler. Durum güncellendikten sonra bir işlem yapmak istiyorsanız, setState()'in ikinci parametresi olarak bir geri çağrı fonksiyonu kullanmalısınız.

3. componentDidMount ve useEffect arasındaki temel fark nedir?

componentDidMount, sınıf bileşenlerinde bileşen DOM'a ilk kez bağlandığında yalnızca bir kez çalışır. useEffect ise fonksiyonel bileşenlerde hem ilk bağlandığında (mount) hem de bağımlılıkları değiştiğinde (update) çalışabilir. useEffect'in ikinci parametresi olan bağımlılık dizisi, ne zaman tekrar çalışacağını kontrol etmenizi sağlar.

4. Prop drilling sorununu sınıf bileşenlerinde nasıl çözeriz?

Sınıf bileşenlerinde prop drilling sorununu çözmek için React Context API veya Higher-Order Components (HOCs) ve Render Props gibi desenler kullanılabilir. Context API, belirli bir veri türünü bileşen ağacının derinliklerinde doğrudan erişilebilir kılar. HOCs ve Render Props ise bileşenler arası mantık ve veri paylaşımını kolaylaştırır.

5. Eski bir React projesini Hooks'a geçirmek zor mudur?

Eski bir React projesini Hooks'a geçirmek, projenin büyüklüğüne ve karmaşıklığına bağlı olarak değişebilir. Küçük projeler için nispeten kolay olabilirken, büyük ve karmaşık projeler için dikkatli bir planlama ve aşamalı bir geçiş stratejisi gerektirebilir. Ancak, Hooks'un sunduğu avantajlar (daha temiz kod, daha kolay mantık paylaşımı) genellikle bu çabaya değerdir.

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Gönder

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.
Exit mobile version