Kas.14

React Hooks, useState() ve useEffect() Kullanımları


HOOKS ile State Yönetimi

React’ta iç içe çok fazla Component kullanıldığında artık bir zaman sonra bunların yönetimi ve projenin daha da ilerlemesi oldukça güç bir hale geliyor. Özellikle de dallanmış olan Component’lerde en uçlardakinin güncellenmesi ile diğer ona bağlı üst Component’lerin de otomatik olarak re-render olması bir süre sonra performans sorunlarına da neden oluyor. Üst Component’lerden alt Component’lere de sürekli olarak props’larla veri aktarmak gerektiğinde artık insan bu React’a neden bulaştım diye iç geçirmeye başlıyor. Çözüm olarak React’ın daha gelişmiş Component sistemi olak Higher Order Component sistemi de kullanılıyordu. HOC’un amacı; sarmaladığı Component’lere ortak özellikler kazandırmak ve ortak olarak yönetilmesini sağlamak. Ama bu da iyi bir çözüm değildi…

Hooks Nedir

React’ın props aktarma mimarisinden sıkılan geliştiriciler sürekli olarak çözümler bulmaya çalıştı. Çözümlerden en yaygın olanı Redux kullanmaktı. Redux, en basit bir kök Object içinde her bir Component için ayrı ayrı olarak verileri tutması, Component’lerin de sadece kendisi için ayrılan izole verileri sürekli olarak dinleyerek kendisini re-render etmesi yöntemine dayanır. Tanım olarak basit gibi görünse de Redux’a geçemeyen çok fazla geliştirici oldu. Aslında mantığını kavradıktan sonra kullanımı o kadar da zor değildi. Fakat Redux’ın da kötü bir tarafı vardı, o da çok fazla dosya kalabalığı ve kod fazlalılığı oluşturmaktı. Her bir Component’i yönetmek için birer Reducer ve birer de Actions dosyası oluşturmak, bunları Component’lerle de birbirine bağlamak derken artık bir kodu takip ederken dosyalar arasında da çok fazla sık sık git gel yapmak zorunda kalıyorduk. En ufak bir işi yapmak için bile çok fazla efor sarfetmeye başladık. Sonuçta projenin sürdürülebilirliği bozulmuyordu ama kontrol edilmesi zorlaşıyordu. Bu zorluk sadece geliştiriciler açısından değil, bilgisayar tarafından da sorunlara yol açıyor. Class içinde sürekli birbirini sarmalayan başla Class’lar, bir süre sonra anlamsızlaşmaya başlıyor.

Redux’ın da kötü yönlerini gören geliştiricilerden Hooks adında bir modül geliştirdi. Gelişim süreci de tam 5 yıl sürdü. İlk başlarda Vue Framework’ü ile kullanılmaya başladı. Sonrasında React’a da entegre edilmeye çalışıldı ve bir süre alpha sürümünde stabil olmayarak test amaçlı kullanıldı. Nihayet 16.8.0 sürümünde Hooks artık built-in oldu, yani ekstradan modül olarak kurmaya gerek kalmadı. Hooks, Class’sız şekilde React’in özelliklerini daha fazla kullanmanızı sağlar. Şunu da belirtmekte fayda var, Hooks kullanmak tamamen sizin tercihinize kalmıştır.
Hooks, Class içinde çalışmaz, fonksiyon içinde çalışır. Evet, bu tanım React ile ilgili şu ana kadar kafanızda oturmuş olan düşüncelerinizi tamamen bozacak bir tanım. React, aslında Class’lardan daha çok fonksiyonlar ile çalışılmaya daha yatkındır. Class’larda sürekli olarak state yönetimi, prop yönetimi, herhangi bir olay yöneticisinin bind edilmesi gibi sorunlarla uğraşır. Ayrıca JavaScript’te Class kullanımı diğer OOP dillerine göre çok farklıdır. Bu durum hem biz geliştiricilerin hem de yorumlayıcıların (bilgisayarın) kafasını karıştırmaktadır. Fonksiyonel programlama yönteminde işler biraz daha kolaylaşıyor.

React’ın gelişim planında ilerleyen zamanlarda Class’ların kaldırılmayacağı yönünde bir ifade var. Yani bu durum kullanıcılara kullanım özgürlüğü tanıyor. Bazen çok fazla özgür kalmak da işleri çok fazla karmaşık hale getirebiliyor.

Peki, Hooks ne zaman kullanılmalı?

Eğer fonksiyon Component’lerle çalışıyorsanız ve bir state yönetimine ihtiyaç duyarsanız, o Component’i tekrar bir Class’a çevirmeniz gerekmiyor. Doğrudan Hooks bağlayarak state yönetimi yapabilirsiniz.

Hooks’u incelerken hem normal Class yapısı ile hem de Hooks yapısı ile örneklerimizi yapacağız. Böylelikle karşılaştırma yaparak hangi kullanım metodunun proje ihtiyacınıza göre uygun olabileceğini daha rahat ayır edebilirsiniz.

State Hook: useState()

Hooks’un gelmesi ile birlikte gitmesi gereken şeyler de oldu. LifeCycle’da componentDidMount(), componentDidUpdate() ve componentWillUnmount() bulunuyordu. Artık Hooks kullanacağınız zaman bunlara gerek kalmıyor, onların yerine hepsini kapsayan useEffect() metodunu kullanmak gerekiyor.

Componet’lerde state kullanabilmek için onu bir Class’a çevirmek gerekiyordu, yani fonksiyon Component’lerde state kullanılamıyordu. Ancak Hooks sayesinde artık fonksiyonel Component’lerde de state tutulabilir.

Fonksiyonel bir Component’e aşağıdaki gibi useState() metodunu dahil edebilirsiniz. useState() metodu, state’te bir değişken tanımlar ve doğrudan değişkenin adı ile çağırma yapmamızı sağlar (Yani this.state.degiskenAdi yerine doğrudan degiskenAdi şeklinde).

Normalde değişkenler fonksiyon tamamlandığında kaybolur, ancak useState() değişkenleri global tutar, yani kaybolmaz.

import React, { useState } from 'react';

Basit bir örnek ile başlayalım. Bu örnekte butona her tıklandığında sayıyı birer birer artırsın.

import React, { useState } from 'react';
function Ornek() {
  const [toplam, sayiyiArtir] = useState(0);
  return (
    <div>
      <p>Toplam {toplam} defa tıkladınız.</p>
      <button onClick={ () => sayiyiArtir(toplam + 1) }>Sayıyı artır</button>
    </div>
  );
}

Örneğimizde Ornek isimli bir fonksiyon tanımladık. Fonksiyonun en üst seviyesinde toplam adında değişken sayiArtir isminde fonksiyon tanımladık.

useState(), iki adet değer kullanır. Bunlardan birincisi değişken adı (toplam), diğeri de değişkeni güncelleyecek olan fonksiyon (sayiyiArtir). Bu kullanım bir Class’taki this.state.toplam ve this.setState() metoduna benzer. Köşeli parantez kullanımın sebebi de EcmaScript 6 özelliklerinden Array destruction (parçalama) özelliğidir. Böylece tek seferde iki farklı değişken oluşturulur. Eğer bu şekilde kullanmasaydık aşağıdaki gibi kullanmamız gerekirdi (Aşağıdaki şekilde de kullanmanızı önermiyorum).

const toplamState = useState(0);
const toplam = toplamState[0];
const sayiyiArtir = toplamState[1];

useState(0) ile de varsayılan değerini 0 olarak belirttik.

useState() ilk çağırıldığında değişkene varsayılan değeri verir. Tekrar render işlemlerinde çağırıldığında o anki değerini verir.

Eğer çoklu state kullanmak isterseniz her birini ayrı ayrı tanımlamanız gerekir.

function Alisveris () {
  // Birden fazla state değişkeni bildir!
  const [para, parayiSay] = useState(100000);
  const [liste, listeyiTut] = useState( [ { id:0, isim: ‘Elma’} , { id:1, isim: ‘Süt} ] );
  const [market, marketSec] = useState([{ isim: 'Market 1' }]);
…

return() metodunda da değişken kullanımını direkt {toplam} olarak yazdık. Butona da onClick olay yöneticisi ekleyip sayiyiArtir fonksiyonuna parametre olarak toplam değerine 1 ekleyerek değer gönderdik.

Aynı örneği bir de Classs ve state yönetimi ile yapalım…

import React, { Component } from 'react';
class Ornek extends React.Component {
  constructor() {
    super();
    this.state = { toplam: 0 };
  }
  render() {
    return (
      <div>
        <p>Toplam {this.state.toplam} defa tıkladınız.</p>
        <button onClick={ () => this.setState( { count: this.state.toplam + 1 } ) }>Sayıyı artır</button>
      </div>
    );
  }
}

Efekt Hook: useEffect()

useEffect() metodu, React Class LifeCycle metotlarından componentDidMount(), componentDidUpdate() ve componentWillUnmount() metotlarının kombinasyonudur. Her render’da tekrar çağırılır.
useState() ile yaptığımız sayı artırma örneğimize useEffect()’i de katarak devam edelim…

import React, { useState, useEffect } from 'react';

function Ornek() {
  const [toplam, sayiyiArtir] = useState(0);

  // componentDidUpdate metodu yerine…
  // toplam değeri değiştiğinde çalışır.
  useEffect(() => {
       console.log(`Toplam tıklama sayısı: ${toplam }`;
  }, [toplam] );
 
  // componentDidMount ve componentWillUnmount metodu yerine…
  useEffect(() => {
      console.log(“Sayfa başlatıldı.)”;
      return () => {
         console.log(“Sayfa kaldırılıyor.”);
      }
  }, []);
  return (
    <div>
      <p>Toplam {toplam} defa tıkladınız.</p>
      <button onClick={ () => sayiyiArtir(toplam + 1) }>Sayıyı artır</button>
    </div>
  );
}

useEffect() metodna ikinci parametre verilmese her render işleminde tekrar çalışır, aynı componentWillUpdate() metodu gibi. Eğer parametre olarak bir değer verilirse (Örnekte [toplam] verilmiştir), sadece parametre olarak verilen değişken veya değişkenler güncellendiğinde metot çalışır.

Eğer useEffect() metoduna ikinci parametre verilmezse, (yani sadece [] kullanılır) componentDidMount() ve componentWillUnmount() metotları gibi çalışır. Metoda girildiğinde ilk olarak componentDidMount() gibi çalışır. Bu işlemi tek bir seferde yapması için de metot içinde bir fonksiyon return ediyoruz. Böylece metot çağırıldığında artık direkt fonksiyon çağırılacak. Fonksiyonda da componentWillUnmount() için yapılacak işler yapılıyor. Örneğimizde ilk olarak konsolda sayfanın başladığını söylüyor. Ancak sonrasında bir fonksiyon return ediliyor. Tekrar bu metot çağırıldığında fonksiyon çalışacağı için sayfa kaldırılıyor diye bilgi verecektir.

Hooks Kuralları

• Kural 1: Hooks’u Sadece En Üst Seviyede Çağırın

Herhangi bir döngü, koşul veya iç içe geçmiş alt fonksiyonlardan Hooks çağırılmaz. Her zaman için en üst seviyede kullanılır. React’ın çoklu useState() ve useEffect() kullanımları arasında Hooks durumunu bu şekilde korur.

• Kural 2: Hooks’u Sadece React Fonksiyonlarından Çağırın

Hooks React’a aittir, bu nedenle sadece React fonksiyonları tarafından çağırılmalıdır. Diğer normal fonksiyonlar ile çağırılmamalıdır. Bu kuralı uyulmalı ve bir Component’te tüm kod mantığının açıkça görülebilir ve anlaşılabilir olmasını sağlamalıyız.

• Kural 3: ESLint Eklentisi Kullanın

İlk iki kuralı uygulayan ve hatalı kullanımlarda uyaran ESLint eklentisi bulunmaktadır, bunu kullanın.

npm install eslint-plugin-react-hooks –save

ESLint kodların belli kurallara göre analiz edilmesini sağlayan, kodu daha tutarlı hale getiren ve hatalı durumlarda uyaran bir araçtır. ESLint kurulumu aşağıdaki gibidir.

npm install eslint –save

Kurulumdan sonra proje klasöründe .eslintrc adında bir dosya oluşturun (Windows’ta isimsiz dosya oluşturalamaz. Bu nedenle Notepad’i açıp doğrudan bu dosya ismi ile kaydedin). Sonrasında da aşağıdaki gibi kuralları bu dosyaya ekleyin (Açıklama satırlarını silin).

{
  "plugins": [
    "react-hooks"
  ],
  "rules": {
    "react-hooks/rules-of-hooks": "error",  //Hooks kurallarını kontrol eder
    "react-hooks/exhaustive-deps": "warn" //Efekt bağımlılıklarını kontrol eder
  }
}

Web Tasarımı ve Web Programlama 2020

Yorum bırak

Yorum