CodeNomadTR
Web geliştirici
Geçen ay eski bir projeyi devraldım, liste ekranı 300 satırlık bir component olmuş. Kullanıcı bir input'a yazı yazdığında bütün tablo yeniden render oluyor, haliyle takılmalar başlıyor. İşin kötüsü bunu fark etmek için ne React DevTools'un profiler'ını düzgün kullanmayı biliyordum ne de nereden başlayacağımı. Birkaç haftada kendimce bir yöntem oturttum, paylaşayım.
Önce React DevTools'un Profiler sekmesinde "Highlight updates when components render" ayarını açtım. Bu tek başına gözle görülür bir fark yaratıyor, hangi kutu yanıp sönüyor diye bakınca insan nerede gereksiz iş döndüğünü hemen anlıyor. Sonra kaydı alıp flame graph'a bakıyorum, ama orada kaybolmamak lazım; önce sadece en uzun süren birkaç render'a odaklanıyorum.
İkinci adımda state'i yukarı taşıma meselesine baktım. Bizim durumda arama input'unun state'i en üst seviyedeydi, dolayısıyla her tuş vuruşunda tüm ağaç etkileniyordu. Input'u ayrı bir component'e alıp state'i oraya hapsettim, sadece debounce edilmiş değeri yukarı gönderdim. Tek başına bu değişiklik takılmayı büyük ölçüde kesti.
Sonra context kullanımını gözden geçirdim. Bir context'e koca bir obje koymuşuz, içindeki tek bir alan değişince onu tüketen her component render oluyor. Context'i parçalara ayırdım, sık değişen değerleri ayrı tutum. useMemo ve useCallback'i de körü körüne serpmedim; sadece profiler'da gerçekten sorun çıkaran yerlere ekledim. Her yere memo yazmak kodu okunmaz hale getiriyor, faydası da çoğu zaman ölçülemeyecek kadar az oluyor.
Bir de key meselesi var. Listede index'i key olarak kullanmışız, filtreleme yapınca React yanlış eşleştirme yapıp gereksiz DOM işi çıkarıyordu. Stabil bir id'ye geçince bu da düzeldi. Bunu ilk bakışta kimse fark etmiyor ama profiler'da commit sürelerine bakınca ortaya çıkıyor.
Şunu da ekleyeyim, her render kötü değil. Bazen bir component'in render olması sanıldığından çok daha ucuz, asıl maliyet DOM güncellemesinde veya alt ağaçta oluyor. O yüzden ölçmeden optimize etmemeye çalışıyorum artık, yoksa saatlerce useCallback ekleyip hiçbir şey kazanmamış oluyorum.
Sizin ekipte bu iş nasıl yürüyor, profiler'a düzenli bakan biri var mı yoksa sorun çıkınca mı açıyorsunuz?
Önce React DevTools'un Profiler sekmesinde "Highlight updates when components render" ayarını açtım. Bu tek başına gözle görülür bir fark yaratıyor, hangi kutu yanıp sönüyor diye bakınca insan nerede gereksiz iş döndüğünü hemen anlıyor. Sonra kaydı alıp flame graph'a bakıyorum, ama orada kaybolmamak lazım; önce sadece en uzun süren birkaç render'a odaklanıyorum.
İkinci adımda state'i yukarı taşıma meselesine baktım. Bizim durumda arama input'unun state'i en üst seviyedeydi, dolayısıyla her tuş vuruşunda tüm ağaç etkileniyordu. Input'u ayrı bir component'e alıp state'i oraya hapsettim, sadece debounce edilmiş değeri yukarı gönderdim. Tek başına bu değişiklik takılmayı büyük ölçüde kesti.
Sonra context kullanımını gözden geçirdim. Bir context'e koca bir obje koymuşuz, içindeki tek bir alan değişince onu tüketen her component render oluyor. Context'i parçalara ayırdım, sık değişen değerleri ayrı tutum. useMemo ve useCallback'i de körü körüne serpmedim; sadece profiler'da gerçekten sorun çıkaran yerlere ekledim. Her yere memo yazmak kodu okunmaz hale getiriyor, faydası da çoğu zaman ölçülemeyecek kadar az oluyor.
Bir de key meselesi var. Listede index'i key olarak kullanmışız, filtreleme yapınca React yanlış eşleştirme yapıp gereksiz DOM işi çıkarıyordu. Stabil bir id'ye geçince bu da düzeldi. Bunu ilk bakışta kimse fark etmiyor ama profiler'da commit sürelerine bakınca ortaya çıkıyor.
Şunu da ekleyeyim, her render kötü değil. Bazen bir component'in render olması sanıldığından çok daha ucuz, asıl maliyet DOM güncellemesinde veya alt ağaçta oluyor. O yüzden ölçmeden optimize etmemeye çalışıyorum artık, yoksa saatlerce useCallback ekleyip hiçbir şey kazanmamış oluyorum.
Sizin ekipte bu iş nasıl yürüyor, profiler'a düzenli bakan biri var mı yoksa sorun çıkınca mı açıyorsunuz?