23 Nisan, 2024, Salı

React.memo

React.memo

src/components klasörleri altında Counter.js adında bir component oluşturduk.

//src/components/Counter.js
import { View, Text, StyleSheet } from "react-native";
import React, { useState } from "react";

const Counter = () => {
  const [count, setCount] = useState(0);

  return (
    <View style={styles.container}>
      <Text style={styles.text}>{count}</Text>
      <Button title="Arttır" onPress={() => setCount(count + 1)} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    justifyContent: "center",
    alignItems: "center",
  },
  text: {
    fontSize: 24,
  },
});

export default Counter;

Bu componenti App.js içerisinde görüntüledik.

//App.js
import { StyleSheet, View } from "react-native";
import Counter from "./src/components/Counter";

export default function App() {
  return (
    <View style={styles.container}>
      <Counter />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
});

Header isminde başka bir componentimiz daha olsa ve bunu Counter componenti içinde render edelim. Ayrıca console.log ile componentlerin render edilmesini gözlemleyelim.

//src/components/Counter.js
import { View, Text, StyleSheet } from "react-native";
import React from "react";

const Header = () => {
  console.log("Header component re-render");
  return (
    <View>
      <Text style={styles.container}>Header</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    marginBottom: 60,
    borderBottomWidth: 2,
  },
});
export default Header;
//src/components/Counter.js
import { View, Text, StyleSheet } from "react-native";
import React, { useState } from "react";
import Header from "./Header";

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)} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    justifyContent: "center",
    alignItems: "center",
  },
  text: {
    fontSize: 24,
  },
});

export default Counter;

Açtığımızda Counter componenti ve ardından Header componentinin render edildiği log u görülüyor.

State güncellediğimizde yani arttır butonuna bastığımızda tekrardan counter ve header componenti render ediliyor.

Burdaki count arttığı anda Counter componenti evet render edilmeli çünkü üzerindeki bir state değişmeli fakat Header componentini ilgilendiren bir durum yok o anda count un değişmesi Header ı etkilememeli, Header ı tekrar tekrar render etmemeli. Çünkü Header ı alakadar eder bir durum bulunmamaktadır.

Örneğin biz maliyetli bir işlem yapıyoruz, elimizde 1000 elaman 10000 elemanlı bir array olmalı ve bunu da Header componentinde göstermeliyiz ve bu işlemi de bir kere yapmak istiyoruz.

//src/components/Counter.js
import { View, Text, StyleSheet } from "react-native";
import React from "react";

const Header = () => {
  console.log("Header component re-render");

  const arr = new Array(5).fill().map(() => Math.floor(Math.random() * 10));

  return (
    <View>
      <Text style={styles.container}>Header</Text>
      <Text>{JSON.stringify(arr)}</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    marginBottom: 60,
    borderBottomWidth: 2,
    alignItems: "center",
    paddingBottom: 10,
  },
});
export default Header;

Array ilk açtığımızda oluşturuldu. Fakat count u değiştirdiğimiz anda da Header componenti tekrar render edildiği için Array in oluşturulması için gerekli hesaplama tekrar baştan yapıldı ve yeni bir Array elde ettik.

Burda yaptığımız işlem 5 elemanlı bir array oluşturmak ancak burada yaptığımız işlem çok daha maliyetli bir işlem olabilirdi. Ve dolayısıyla biz butona her bastığımızda gereksiz yere bu component render edilmiş olacaktı. İşte bizim bu durumlardan kaçınmamız gerekiyor.

React doğası gereği bir component içerisindeki bir state güncellendiği anda o component içindeki return de gördüğümüz ne varsa render ediliyor, Header da buna dahil. Ancak bu bizim için istenmeyen bir durum.

React.memo isminde bir tanım var. Bunun yaptığı şey ilgili componentin aldığı önceki property leri ve yeni property leri karşılaştırır. Eğer bunlar aynı ise tekrar render etmez. Ama farklı ise ancak o zaman render edecektir.

 

İlk kez render edildiğinde Header ve Counter componentinin render edildiğini görürüz. Daha sonra count u arttırdığımızda sadece Counter componentinin render edildiğini gözlemleriz, ne kadar arttırırsam arttırayım Header componenti hiç bir şekilde değişmeyecektir ne zamana kadar peki? Header componentinin aldığı property ler değişene kadar..

Zaten Header componenti hiçbir property almadığı için önceki property lerle şimdikiler aynı öncekinden kasıt count un değeri değişmeden/güncellenmeden önceki hali.

Header componenti bir property alsaydı mesela count u alsaydı bir property olarak; count un değeri (butona basıldığına) her defasında değişeceği için Header da tekrar tekrar render edilecektir.

Neden?

Çünkü Header componentindeki property olarak verdiğimiz count un değeri ilk kez render edildiğinde 0 dı.
Ardından count un değeri 1 olduğu anda memo şunu yapıyor 0 la 1 eşit mi? Değil o zaman componenti render et.
1 olduktan sonra da Arttır butonuna basılırsa count 2 oluyor memo tekrar bakıyor 1 ile 2 birbirine eşit mi? Değil o zaman render et.

Biz diyelim ki; aldığımız count un değerine göre Header componentinde count elemanlı bir array oluşturuyoruz. Başlangıçta count 0 olduğu için array in içi de boş, count arttırdıkça buradaki array in de eleman sayısı artıyor.

//src/components/Counter.js
import { View, Text, StyleSheet } from "react-native";
import React from "react";

const Header = ({ count }) => {
  console.log("Header component re-render");

  const arr = new Array(count).fill().map(() => Math.floor(Math.random() * 10));

  return (
    <View>
      <Text style={styles.container}>Header</Text>
      <Text>{JSON.stringify(arr)}</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    marginBottom: 60,
    borderBottomWidth: 2,
    alignItems: "center",
    paddingBottom: 10,
  },
});
export default React.memo(Header);

count un değeri 5 ten küçük olduğu sürece count u gönder aksi halde daima 5 gönder. Değer 5 olana kadar Header componenti tekrar tekrar render olacaktır. Ancak 5 olduktan sonra daima 5 gönderileceği için tekrar tekrar Header componenti render edilmeyecektir.

//src/components/Counter.js
import { View, Text, StyleSheet, Button } from "react-native";
import React, { useState } from "react";
import Header from "./Header";

const Counter = () => {
  const [count, setCount] = useState(0);

  console.log("Counter component re-render");

  return (
    <View style={styles.container}>
      <Header count={count < 5 ? count : 5} />

      <Text style={styles.text}>{count}</Text>
      <Button title="Arttır" onPress={() => setCount(count + 1)} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    justifyContent: "center",
    alignItems: "center",
  },
  text: {
    fontSize: 24,
  },
});

export default Counter;

React.memo; önceki property lerle yeni property leri karşılaştırıyor ve eğer farklılık varsa ancak o zaman ilgili component render ediliyor ve böylelikle de bir re-render optimizasyonu sağlanmış oluyor.

 

Önceki İçerik
Sonraki İçerik
0 0 votes
Article Rating
Subscribe
Bildir
guest
0 Yorum
Inline Feedbacks
View all comments
İLGİLİ MAKALELER

Popüler Yazılar

En Çok Yorum Alanlar

Son Yorumlar