Foruma hoş geldin 👋, Ziyaretçi

Forum içeriğine ve tüm hizmetlerimize erişim sağlamak için foruma kayıt olmalı ya da giriş yapmalısınız. Foruma üye olmak tamamen ücretsizdir.

React'te Context API ile Theme (dark/light mode) implementasyonu yaparken karşılaştığım flash sorunu ve çözümü

✖ Kapat
Duyuru
✖ Kapat
Duyuru

nexter

Üye
Katılım
14 Mart 2026
Mesajlar
50
Merhaba arkadaşlar, bugün başımı çok ağrıtan bir sorundan ve nasıl çözdüğümden bahsedeceğim. React'te Context API kullanarak dark/light mode (tema) geçişi yapmak oldukça popüler bir yöntem. Ben de projemde bu yapıyı kurdum, her şey harika çalışıyordu derken, sayfayı yenilediğimde veya ilk açtığımda kafayı yemiştim! Sayfa önce varsayılan light temada bir anlığına beliriyor, sonra kullanıcının tercih ettiği dark tema uygulanıyordu. İşte bu istenmeyen "flash" olayını nasıl engellediğimi anlatacağım.

🔥 Karşılaştığım Flash Sorunu
Sorunun kaynağı, tema bilgisinin (örneğin `localStorage`'dan okunmasının) React bileşen ağacı render edildikten sonra gerçekleşmesiydi. Yani, ilk render sırasında tema Context'i henüz `localStorage`'daki değeri okuyamadığı için varsayılan değeri (benim durumumda `'light'`) sağlıyordu. Birkaç milisaniye sonra `useEffect` çalışıp doğru değeri okuduğunda, tema değişiyor ve o çirkin flash efektini görüyorduk.

⚙️ Çözüm: Tema Bilgisini Render'dan Önce Belirlemek
Bu sorunu çözmek için, temel fikir, ilk HTML'in sunucudan (veya ilk istemci render'ından) önce doğru tema class'ı ile gelmesini sağlamak. Yani, React'in ilk render'ı için doğru tema değerini önceden hazırlamamız gerekiyor.

İşte benim kullandığım en temiz çözüm. İlk adım, Context'imizi ve Provider'ımızı oluşturmak. Burada `theme` state'ini, `localStorage`'dan okuma işlemini bir fonksiyonla yapıyoruz.

JavaScript:
// ThemeContext.js
import React, { createContext, useState, useEffect, useContext } from 'react';

const ThemeContext = createContext();

// localStorage'dan temayı okuyan yardımcı fonksiyon
const getInitialTheme = () => {
  if (typeof window !== 'undefined' && window.localStorage) {
    const storedPref = window.localStorage.getItem('color-theme');
    if (typeof storedPref === 'string') {
      return storedPref;
    }

    const userMedia = window.matchMedia('(prefers-color-scheme: dark)');
    if (userMedia.matches) {
      return 'dark';
    }
  }
  // Varsayılan tema olarak 'light' döndürüyoruz.
  // Eğer sistem tercihini baz almak isterseniz yukarıdaki media query'yi kullanın.
  return 'light';
};

export const ThemeProvider = ({ initialTheme, children }) => {
  // State'i, dışarıdan gelebilecek `initialTheme` veya yardımcı fonksiyonumuzla başlatıyoruz.
  const [theme, setTheme] = useState(getInitialTheme);

  const rawSetTheme = (rawTheme) => {
    const root = window.document.documentElement;
    const isDark = rawTheme === 'dark';

    root.classList.remove(isDark ? 'light' : 'dark');
    root.classList.add(rawTheme);

    localStorage.setItem('color-theme', rawTheme);
  };

  // Theme değiştiğinde, DOM'u ve localStorage'ı güncelle.
  useEffect(() => {
    rawSetTheme(theme);
  }, [theme]);

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

export const useTheme = () => useContext(ThemeContext);

🔧 Kritik Adım: _document.js ve İlk Render
Bu kısım, Next.js gibi bir framework kullanıyorsanız çok daha kolay. Ancak vanilla React (CRA) ile de çözebiliriz. Next.js'de, `pages/_document.js` dosyası oluşturup, sunucu tarafında çalışan bir script ile `localStorage` kontrolü yapıp, HTML etiketine doğru class'ı ekleyebiliriz.

Ama ben CRA ile nasıl yaptığımı anlatayım. Ana `index.html` dosyasındaki `<body>` etiketinden hemen sonra, `localStorage`'ı kontrol eden küçük bir inline script ekledim. Bu script, React uygulaması yüklenmeden önce çalışır ve doğru class'ı ekler.

HTML:
<!-- public/index.html -->
<!DOCTYPE html>
<html lang="tr">
  <head>...</head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>

    <!-- TEMA FLASH SORUNU ÇÖZÜMÜ -->
    <script>
      (function() {
        // Sayfa yüklenmeden önce temayı belirle
        var storedTheme = localStorage.getItem('color-theme');
        var systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
        var initialTheme = storedTheme || systemTheme || 'light';

        document.documentElement.classList.add(initialTheme);
      })();
    </script>
  </body>
</html>

Artık, uygulamamız ilk açıldığında, `<html>` etiketi doğru tema class'ına (`dark` veya `light`) sahip olacak. Context'imizin `getInitialTheme` fonksiyonu da aynı mantıkla çalıştığı için, ilk render'da flash olmayacak. Context'teki `useEffect` zaten aynı değeri `localStorage`'a yazacak, böylece senkronizasyon sorunu kalmayacak.

✅ Sonuç ve Performans
Bu yöntemi uyguladıktan sonra, tema geçişleri hem kullanıcı deneyimi açısından kusursuz hem de performans açısından sorunsuz hale geldi. Flash sorunu tamamen ortadan kalktı. Context yapısı sayesinde, tema değerine uygulamanın herhangi bir yerinden `useTheme` hook'u ile erişip, kolayca değiştirebiliyorum.

Siz React'te tema yönetimi için nasıl bir yöntem izliyorsunuz? Context API dışında (Redux, Zustand) state yönetim kütüphaneleri ile benzer bir flash sorunu yaşadınız mı? Ya da Next.js'de `getServerSideProps` veya `getInitialProps` ile daha farklı bir çözüm mü uyguluyorsunuz? Yorumlarda deneyimlerinizi paylaşın, tartışalım!
 

Tema özelleştirme sistemi

Bu menüden forum temasının bazı alanlarını kendinize özel olarak düzenleye bilirsiniz.

Zevkine göre renk kombinasyonunu belirle

Tam ekran yada dar ekran

Temanızın gövde büyüklüğünü sevkiniz, ihtiyacınıza göre dar yada geniş olarak kulana bilirsiniz.

Geri