src/components klasörü altında Users.js isimli component oluşturuyoruz. Bu componenti de Counter componenti içinde çağırdık.
const user = {
id: 1,
name: “Mehmet”,
};
diyerek User componentine user isminde bir property tanımladık. bu şekilde kullandık.
//src/components/Counter.js import { View, Text, StyleSheet, Button } from "react-native"; import React, { useState } from "react"; import Header from "./Header"; import User from "./User"; const Counter = () => { const [count, setCount] = useState(0); console.log("Counter component re-render"); const user = { id: 1, name: "Mehmet", }; return ( <View style={styles.container}> <Header /> <Text style={styles.text}>{count}</Text> <Button title="Arttır" onPress={() => setCount(count + 1)} /> <User user={user} /> </View> ); }; const styles = StyleSheet.create({ container: { justifyContent: "center", alignItems: "center", }, text: { fontSize: 24, }, }); export default Counter;
//src/components/User.js import { View, Text, StyleSheet } from "react-native"; import React from "react"; const User = ({ user }) => { console.log("User component re-render"); return ( <View style={style.container}> <Text>User</Text> <Text>{JSON.stringify(user)}</Text> </View> ); }; const styles = StyleSheet.create({ container: { marginTop: 40, borderTopWidth: 2, paddingTop: 10, alignItems: "center", }, }); export default React.memo(User);
User componentine React.memo yu koydum, memo kullanıyorsak ve gönderilen propertyler aynıysa hep tekrar tekrar render edilmemesi gerekir. Gördügümüz üzere veri aynı olmasına rağmen tekrar tekrar render ediyor.
React.memo(User); şeklinde ifade ettik ancak Arttır butonuna bastığımızda Counter ve User componentinin tekrar tekrar render edildiğini gözlemledik.
Bunun sebebi verinin içeriği aynı, JavaScriptte {} === {} bir obje denk midir bir objeye diye sorguladığımızda false çıkar. Veya bir [] === [] bir array denk midir bir diğer bir boş array a yine false çıkar.
Burdaki yapılan karşılaştırma sadece verinin içeriği ile alakalı değil. Burda bir primitive (ilkel) veri türleri var JavaScriptte bir de referans tipli veri türleri var. Object de referans tipli veri türlerinden bir tanesi ve bu object her bir Counter componentinin render edilmesinden sonra yeniden bellekte referanslanıyor yani referansı değişiyor biz her defasında User componentine referansı değişmiş bir veriyi gönderiyoruz. Ve React.memo bakıyor, sadece verinin içeriğini kontrol etmiyor bu bellekteki referansına da bakıyor, referansı farklı olduğu için tekrardan render etmem lazım çünkü bu farklı bir veri diye algılayıp tekrardan kendini render ediyor. Problem referansın değişmesi..
Bu sorun primitive ifadelerde olmaz; number, string, boolean veri türlerinde olmaz.
const user = “merhaba”; şeklinde string bir ifade belirtirsek sadece Counter componenti render edilir. Burada object veya array kullanırsam işte o zaman referans değiştiği için tekrar tekrar render edilme durumu ortaya çıkıyor.
Bu durumdan kurtulmak için eğer user objesini component içerisinde kullanmam gereken bir durum yoksa örneğin bir state e bağlı olarak bunun değerini değiştirmiyorsa bu sabit olarak kalacaksa bunu componentin dışında tanımlayabilirim böylece bu object bir kere oluşturulacak bir kere bellekte referans gösterilecek bir daha da değişmeyecektir.
//src/components/Counter.js import { View, Text, StyleSheet, Button } from "react-native"; import React, { useState } from "react"; import Header from "./Header"; import User from "./User"; const user = { id: 1, name: "Mehmet", }; const Counter = () => { const [count, setCount] = useState(0); console.log("Counter component re-render"); return ( <View style={styles.container}> <Header /> <Text style={styles.text}>{count}</Text> <Button title="Arttır" onPress={() => setCount(count + 1)} /> <User user={user} /> </View> ); }; const styles = StyleSheet.create({ container: { justifyContent: "center", alignItems: "center", }, text: { fontSize: 24, }, }); export default Counter;
Bu şekilde component dışında tanımlarsak sadece Counter render edilmiş oldu.
Ancak böyle bir durum söz konusu değilse mutlaka componentin içinde kullanmamız gerekiyorsa react in altında useMemo isminde bir hook var bunu aşağıdaki gibi kullanacağız.
useEffect in aynısı. 1. parametreye bir arrow function gireceğiz. 2. parametreye de dependency array gireceğiz. Bu array in içerisinde belirtilmiş olan değerler değiştiğinde ancak şu user ı yeniden oluştur diyebiliriz. içeride de return deyip ilgili object neyse ne dönmek istiyorsak onu yazıyoruz. user ne zaman oluşturulacak sadece component mount edildiğinde dolayısıyla bu user ın referansı asla değişmeyecektir. Arttır butonuna bastığımızda sadece Counter componentinin render edildiğini görürüz.
//src/components/Counter.js import { View, Text, StyleSheet, Button } from "react-native"; import React, { useState, useMemo } from "react"; import Header from "./Header"; import User from "./User"; const Counter = () => { const [count, setCount] = useState(0); const user = useMemo(() => { return { id: 1, name: "Mehmet", }; }, []); console.log("Counter component re-render"); return ( <View style={styles.container}> <Header /> <Text style={styles.text}>{count}</Text> <Button title="Arttır" onPress={() => setCount(count + 1)} /> <User user={user} /> </View> ); }; const styles = StyleSheet.create({ container: { justifyContent: "center", alignItems: "center", }, text: { fontSize: 24, }, }); export default Counter;
İsmi değiştir adında bir buton daha koyuyorum. Butona bastıktan sonra Mehmet yazısının Ahmet olarak değişmesini bekliyoruz. Ancak herhangi bir değişiklik olmadı. name setName state i güncellendi fakat ekrana bir değişim yansımadı çünkü bu object sadece mount anında [] oluşturuldu. Eğer ben name değiştiğinde de bu object baştan oluşturulsun istersem bu dependecy array in içerisine ilgili state i belirtmeliyim. Artık ismi değiştir dediğim zaman ekrandaki isim değişiyor. Ve User componenti de yeniden render edilmiş oluyor. Count u güncellediğimiz sürece User componenti render eilmeyecektir. Ne zaman ki ismi değiştiririm ancak o zaman User comp. render edilecek çünkü render edilmesine ihtiyacım var çünkü isim değişti. İsmi değiştiği için de güncel ismi göstermek için de benim bu componenti render etmem lazım. Dolayısıyla bu user objesi sadece ve sadece name değiştiği anda yeniden hesaplanmasını bellekte yeni bir referans gösterilmesini istiyorum.
//src/components/Counter.js import { View, Text, StyleSheet, Button } from "react-native"; import React, { useState, useMemo } from "react"; import Header from "./Header"; import User from "./User"; const Counter = () =&gt; { const [count, setCount] = useState(0); const [name, setName] = useState("Mehmet"); //burda bir state im daha olsun, başlangıçta Mehmet const user = useMemo(() =&gt; { return { id: 1, name, // state imdeki name i burda doğrudan kullanıyorum. }; }, [name]); // console.log("Counter component re-render"); return ( <View style={styles.container}> <Header /> <Text style={styles.text}>{count}</Text> <Button title="Arttır" onPress={() => setCount(count + 1)} /> <Button title="İsmi Değiştir" onPress={() => setName("Ahmet")} /> <User user={user} /> </View> ); }; const styles = StyleSheet.create({ container: { justifyContent: "center", alignItems: "center", }, text: { fontSize: 24, }, }); export default Counter;