useState

useState, bileşeninize state değişkeni eklemenizi sağlayan bir React Hook’udur.

const [state, setState] = useState(initialState)

Referans

useState(initialState)

Bir state değişkeni bildirmek için bileşeninizin en üstünde useState çağırın.

import { useState } from 'react';

function MyComponent() {
const [age, setAge] = useState(28);
const [name, setName] = useState('Taylor');
const [todos, setTodos] = useState(() => createTodos());
// ...

Ortak düşünce, dizi yapı çözmeyi (array destructuring) kullanarak state değişkenlerini [something, setSomething] olarak adlandırmaktır.

Aşağıda daha fazla örnek bulabilirsiniz.

Parametreler

  • initialState: Başlangıçta state’in alacağı değerdir. Herhangi bir türden bir değer olabilir ancak fonksiyonlar için özel bir davranış vardır. Bu argüman ilk render’dan sonra görmezden gelinir.
    • initialState olarak bir fonksiyon iletirseniz, bu fonksiyona başlatıcı fonksiyon olarak davranılacaktır. Saf olmalıdır, argüman olmamalıdır ve herhangi bir türden değer döndürebilmelidir. React, bileşeni başlatırken başlatıcı fonksiyonunuzu çağıracak ve döndürülen değeri başlangıç state’i olarak saklayacaktır. Aşağıdaki örneği inceleyin.

Döndürülenler

useState her zaman iki değere sahip bir dizi döndürür.

  1. Şu anki state. İlk render sırasında, ilettiğiniz initialState değeri ile aynıdır.
  2. set fonksiyonu state’i başka bir değer ile güncellemenizi ve yeniden render tetiklemenizi sağlar.

Uyarılar

  • useState bir Hook’tur, bu yüzden sadece bileşeninizin üst seviyesinde ya da kendi Hook’larınızda çağırabilirsiniz. Döngülerin ya da koşullu ifadelerin içinde çağıramazsınız. Eğer buna ihtiyacınız varsa, yeni bir bileşen çıkarın ve state’i o bileşene taşıyın.
  • Strict Modda React, kazara oluşan saf olmayan şeyleri bulmanıza yardımcı olmak için başlatıcı fonksiyonunuzu iki defa çağıracaktır. Bu sadece geliştirme sırasında görülen bir davranıştır ve son ürünü etkilemez. Eğer başlatıcı fonksiyonunuz saf ise (ki öyle olmalıdır), bu olması gereken davranışı etkilememelidir. Yapılan çağrılardan birinin sonucu görmezden gelinecektir.

setSomething(nextState) gibi set fonksiyonları

useState tarafından döndürülen set fonksiyonu state’i başka bir değere güncellemenizi ve yeniden render tetiklemenizi sağlar. Bir sonraki state’i direkt olarak ya da önceki state’ten hesaplayan bir fonksiyon iletebilirsiniz:

const [name, setName] = useState('Edward');

function handleClick() {
setName('Taylor');
setAge(a => a + 1);
// ...

Parametreler

  • nextState: State’in olmasını istediğiniz değerdir. Herhangi bir türden değer olabilir ama fonksiyonlar için özel bir davranış vardır.
    • Eğer nextState olarak fonksiyon iletirseniz, o fonksiyon güncelleyici fonksiyon olarak görev alacaktır. Saf olmak zorundadır, bekleme durumunu tek argümanı olarak almalı ve bir sonraki state’i döndürmelidir. React, güncelleyici fonksiyonunuzu sıraya koyacaktır ve bileşeninizi yeniden render edecektir. Bir sonraki render sırasında React, sıradaki güncelleyicilerin hepsini bir önceki state’e uygulayarak bir sonraki state’i hesaplayacaktır. Aşağıdaki örneği inceleyin.

Döndürülenler

set fonksiyonlarının dönüş değeri yoktur.

Uyarılar

  • set fonksiyonu state değişkenini sadece sonraki render için günceller. Eğer state değişkenini set fonksiyonunu çağırdıktan sonra okursanız, hala çağrınızdan önce ekranda gördüğünüz değeri alacaksınız.

  • Eğer sağladığınız yeni değer şu anki state değeri ile aynıysa, ki bu Object.is karşılaştırması ile belirlenir, React bileşeni ve alt elemanlarını yeniden render etmeyecektir. Bu bir optimizasyon işlemidir. Her ne kadar bazı durumlarda React’in alt elemanları atlamadan önce bileşeninizi çağırması gerekse de bu durum kodunuzu etkilememelidir.

  • React state güncellemelerini toplu halde(batches) yapar. React, ekranı tüm olay yöneticileri çalıştıktan ve set fonksyionlarını çağırdıktan sonra günceller. Böylelikle tek bir olay sırasında olacak birden fazla yeniden render engellenmiş olur. Nadiren de olsa, örneğin DOM’a erişmek istediğinizde, React’ı ekranı erken güncellemeye zorlamak için flushSync kullanabilirsiniz.

  • The set function has a stable identity, so you will often see it omitted from Effect dependencies, but including it will not cause the Effect to fire. If the linter lets you omit a dependency without errors, it is safe to do. Learn more about removing Effect dependencies.

  • Render sırasında set fonksiyonu yalnızca mevcut render edilen bileşenin içinde çağırılabilir. React, bileşenin çıktısını görmezden gelecektir ve hemen yeni state ile birlikte render etmeyi deneyecektir. Bu modele nadiren ihtiyaç duyulur ama bunu önceki render’lardan gelen bilgileri saklamak için kullanabilirsiniz. Aşağıdaki örneği inceleyin.

  • Strict Modda React, kazara oluşan saf olmayan şeyleri bulmanıza yardımcı olmak için güncelleyici fonksiyonunuzu iki defa çağıracaktır. Bu sadece geliştirme sırasında görülen bir davranıştır ve son ürünü etkilemez. Eğer güncelleyici fonksiyonunuz saf ise (ki öyle olmalı), bu olması gereken davranışı etkilememelidir. Yapılan çağrılardan birinin sonucu görmezden gelinecektir.


Kullanım

Bileşene state ekleme

Bir ya da birden fazla state değişkeni bildirmek için bileşeninizin üst seviyesinde useState’i çağırın.

import { useState } from 'react';

function MyComponent() {
const [age, setAge] = useState(42);
const [name, setName] = useState('Taylor');
// ...

Ortak düşünce, dizi yapı çözmeyi (destructuring) kullanarak state değişkenlerini [something, setSomething] olarak adlandırmaktır.

useState her zaman iki değere sahip bir dizi döndürür:

  1. Bu state değişkeninin şu anki state’i, başlangıçta belirttiğiniz başlangıç state’ine eşitttir.
  2. set fonksiyonu herhangi bir etkileşim sonucu state’i başka bir değerle değiştirmenizi sağlar.

Ekranda olanı güncellemek için, set fonksiyonunu sonraki herhangi bir state ile çağırın:

function handleClick() {
setName('Robin');
}

React sonraki state’i saklayacaktır, bileşeninizi yeni değerler ile render edecektir ve kullanıcı arayüzünü güncelleyecektir.

Tuzak

set fonksiyonunu çağırmak şu anda çalışan koddaki mevcut state’i değiştirmez:

function handleClick() {
setName('Robin');
console.log(name); // Hala "Taylor"!
}

Bu fonksiyon yalnızca sonraki render etme işleminden başlayarak useState’in ne döndüreceğini etkiler.

Basit useState örnekleri

Örnek 1 / 4:
Sayaç (sayı)

Bu örnekte count state değişkeni bir sayı tutmaktadır. Butona tıklamak bu sayıyı artırır.

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <button onClick={handleClick}>
      Bana {count} defa tıkladın
    </button>
  );
}


State’i bir önceki state’e göre güncelleme

Varsayalım age state’i 42 olsun. Bu yönetici setAge(age + 1) fonksiyonunu üç defa çağırır:

function handleClick() {
setAge(age + 1); // setAge(42 + 1)
setAge(age + 1); // setAge(42 + 1)
setAge(age + 1); // setAge(42 + 1)
}

Ancak bir tıklamadan sonra age değeri 45 yerine 43 olacak! Bunun nedeni ise set fonksiyonunu çağırmanın zaten çalışmakta olan kodda age state değişkenini güncellememesidir. Yani her setAge(age + 1) çağrısı setAge(43) olur.

Bu problemi çözmek için setAge’e bir sonraki state yerine güncelleyici fonksiyon iletebilirsiniz:

function handleClick() {
setAge(a => a + 1); // setAge(42 => 43)
setAge(a => a + 1); // setAge(43 => 44)
setAge(a => a + 1); // setAge(44 => 45)
}

Burada, a => a + 1 sizin güncelleyici fonksiyonunuzdur. Bekleyen state’i alır ve ondan bir sonraki state’i hesaplar.

React güncelleyici fonksiyonlarınızı sıraya koyar. Daha sonra, sonraki render sırasında, bu fonksiyonları aynı sırada çağıracaktır:

  1. a => a + 1 fonksiyonu 42 sayısını bekleyen state olarak alacaktır ve sonraki state olarak 43 döndürecektir.
  2. a => a + 1 fonksiyonu 43 sayısını bekleyen state olarak alacaktır ve sonraki state olarak 44 döndürecektir.
  3. a => a + 1 fonksiyonu 44 sayısını bekleyen state olarak alacaktır ve sonraki state olarak 45 döndürecektir.

Sırada bekleyen başka güncelleme olmadığından dolayı React 45 sayısını güncel state olarak saklayacaktır.

Ortak düşünce, bekleyen state argümanını state değişkeni adının ilk harfi olarak adlandırmaktır; örneğin age için a kullanmak. Ancak, daha açıklayıcı olmasını istiyorsanız prevAge ya da başka bir şey kullanabilirsiniz.

React, geliştirme sırasında güncelleyici fonksiyonlarınızın saf olduğunu doğrulamak için onları iki defa çağırır.

Derinlemesine İnceleme

Güncelleyici kullanmak her zaman tercih edilir mi?

Eğer değiştirdiğiniz state bir önceki state’ten hesaplanıyorsa kodunuzu her zaman setAge(a => a + 1) olarak yazmanız size tavsiye edilmiş olabilir. Bunda bir sorun yoktur ama her zaman gerekli değildir.

Pek çok durumda bu iki yaklaşım arasında bir fark yoktur. React, tıklamalar gibi kasıtlı olarak yapılmış kullanıcı aksiyonları için age state değişkeninin bir sonraki tıklamadan önce güncellendiğine emin olur. Bu, tıklama yöneticisinin, olay yöneticisinin başlangıcında “eski” bir age değişkeni görme riski olmadığı anlamına gelir.

Ancak, aynı olay içinde birden fazla güncelleme yaparsanız, güncelleyiciler yardımcı olabilir. Ayrıca state değişkenine erişmenin sakıncalı olduğu durumlarda da faydalıdırlar (bu durumlarla yeniden render’ları optimize etmeye çalışırken karşılaşabilirsiniz).

Kod olarak kalabılık söz dizimi yerine tutarlığı tercih ediyorsanız, değiştirdiğiniz state bir önceki state’ten hesaplanıyorsa her zaman güncelleyici yazmak mantıklı olacaktır. Eğer state başka bir state değişkeninin önceki state’inden hesaplanıyorsa, güncelleyicileri bir nesne içine koyabilir ve reducer kullanabilirsiniz.

Güncelleyeci ve sonraki state'i direkt olarak iletme arasındaki fark

Örnek 1 / 2:
Güncelleyici fonksiyonu iletme

Bu örnek güncelleyici fonksiyonu iletmektedir bu yüzden “+3” butonu çalışır.

import { useState } from 'react';

export default function Counter() {
  const [age, setAge] = useState(42);

  function increment() {
    setAge(a => a + 1);
  }

  return (
    <>
      <h1>Yaşınız: {age}</h1>
      <button onClick={() => {
        increment();
        increment();
        increment();
      }}>+3</button>
      <button onClick={() => {
        increment();
      }}>+1</button>
    </>
  );
}


State’teki nesneleri ve dizileri güncelleme

State içine nesneleri ve dizileri koyabilirsiniz. React’te, state salt-okunur olarak kabul edilir bu yüzden mevcut nesnelerinizi mutasyona uğratmak yerine değiştirmelisiniz. Örneğin, state’inizde bir form nesnesi varsa, onu mutasyona uğratmayın:

// 🚩 State'teki nesneyi böyle mutasyona uğratmayın:
form.firstName = 'Taylor';

Onun yerine tüm nesneyi yenisiyle değiştirin:

// ✅ State'i yeni bir nesne ile değiştirin
setForm({
...form,
firstName: 'Taylor'
});

Daha fazla bilgi için bu sayfaları okuyun: state içindeki nesneleri güncelleme ve state içindeki dizileri güncelleme.

State içindeki nesnelere ve dizilere örnekler

Örnek 1 / 4:
Form (nesne)

Bu örnekte form state değişkeni bir nesne tutmaktadır. Her input’un tüm formun bir sonraki state’i ile birlikte setForm fonksiyonunu çağıran bir yöneticisi vardır. { ...form } spread sözdizimi state nesnesini mutasyona uğratmak yerine değiştirilmesini sağlar.

import { useState } from 'react';

export default function Form() {
  const [form, setForm] = useState({
    firstName: 'Barbara',
    lastName: 'Hepworth',
    email: 'bhepworth@sculpture.com',
  });

  return (
    <>
      <label>
        Ad:
        <input
          value={form.firstName}
          onChange={e => {
            setForm({
              ...form,
              firstName: e.target.value
            });
          }}
        />
      </label>
      <label>
        Soyad:
        <input
          value={form.lastName}
          onChange={e => {
            setForm({
              ...form,
              lastName: e.target.value
            });
          }}
        />
      </label>
      <label>
        E-posta:
        <input
          value={form.email}
          onChange={e => {
            setForm({
              ...form,
              email: e.target.value
            });
          }}
        />
      </label>
      <p>
        {form.firstName}{' '}
        {form.lastName}{' '}
        ({form.email})
      </p>
    </>
  );
}


Başlangıç state’ini yeniden yaratmaktan kaçınma

React başlangıç state’ini bir defa kaydeder ve sonraki render’larda görmezden gelir.

function TodoList() {
const [todos, setTodos] = useState(createInitialTodos());
// ...

createInitialTodos() fonksiyonunun sonucu sadece başlangıç render’ında kullanılmasına rağmen, bu fonksiyonu hala her render’da yeniden çağırmaktasınız. Eğer bu fonksiyon büyük diziler ya da pahalı hesaplamalar yapıyorsa, bu israfa neden olabilir.

Bu durumu çözmek için bu fonksiyonu, useState’e başlatıcı fonksiyon olarak iletebilirsiniz:

function TodoList() {
const [todos, setTodos] = useState(createInitialTodos);
// ...

Burada createInitialTodos olarak ilettiğinize dikkat edin. Yani burada createInitialTodos() fonksiyonunu çağırmanın sonucunu değil fonksiyonun kendisini iletiyoruz. Eğer useState’e fonksiyon iletirseniz, React bu fonksiyonu sadece başlangıçta çağıracaktır.

React, geliştirme sırasında başlatıcıların saf olduğunu doğrulamak için onları iki defa çağırabilir.

Başlatıcı iletme ve direkt olarak başlangıç state'ini iletme arasındaki farklar

Örnek 1 / 2:
Başlatıcı fonksiyon iletme

Bu örnekte başlatıcı fonksiyon iletilmektedir yani createInitialTodos fonksiyonu yalnızca başlangıçta çalışır. Input’a yazdığınızda olduğu gibi, bileşen yeniden render edildiğinde tekrar çalışmazlar.

import { useState } from 'react';

function createInitialTodos() {
  const initialTodos = [];
  for (let i = 0; i < 50; i++) {
    initialTodos.push({
      id: i,
      text: 'Item ' + (i + 1)
    });
  }
  return initialTodos;
}

export default function TodoList() {
  const [todos, setTodos] = useState(createInitialTodos);
  const [text, setText] = useState('');

  return (
    <>
      <input
        value={text}
        onChange={e => setText(e.target.value)}
      />
      <button onClick={() => {
        setText('');
        setTodos([{
          id: todos.length,
          text: text
        }, ...todos]);
      }}>Ekle</button>
      <ul>
        {todos.map(item => (
          <li key={item.id}>
            {item.text}
          </li>
        ))}
      </ul>
    </>
  );
}


State’i anahtar ile sıfırlama

Listeleri render ederken sık sık key(anahtar) niteliğini göreceksiniz. Ancak, bu başka bir amaca da hizmet etmektedir.

Bir bileşene farklı bir key ileterek onun state’ini sıfırlayabilirsiniz. Bu örnekte Sıfırla butonu, Form’a key olarak ilettiğimiz version state değişkenini değiştirir. key değiştiğinde React, Form bileşenini sıfırdan yeniden yaratır (ve tüm alt elemanlarını) böylelikle state sıfırlanmış olur.

Daha fazla bilgi edinmek için state’i korumak ve sıfırlamak sayfasını inceleyin.

import { useState } from 'react';

export default function App() {
  const [version, setVersion] = useState(0);

  function handleReset() {
    setVersion(version + 1);
  }

  return (
    <>
      <button onClick={handleReset}>Sıfırla</button>
      <Form key={version} />
    </>
  );
}

function Form() {
  const [name, setName] = useState('Taylor');

  return (
    <>
      <input
        value={name}
        onChange={e => setName(e.target.value)}
      />
      <p>Selam, {name}.</p>
    </>
  );
}


Önceki render’lardaki bilgiyi saklama

State’i genellikle olay yöneticileri içinde güncellersiniz. Ancak, bazı nadir durumlarda state’i render’a cevap olarak ayarlamak isteyebilirsiniz — örneğin, bir prop değiştiğinde state değişkenini değiştirmek isteyebilirsiniz.

Çoğu durumda buna ihtiyacınız yoktur:

Bunların hiçbirine uymayan nadir bir durum varsa, bileşeniniz render edilirken set fonksiyonunu çağırarak şu ana kadar render edilmiş değerlere dayalı olarak state’i güncellemek için kullanabileceğiniz bir model vardır.

Aşağıdaki bunu gösteren bir örnektir. CountLabel bileşeni kendisine iletilen count prop’unu render etmektedir:

export default function CountLabel({ count }) {
return <h1>{count}</h1>
}

Diyelim ki sayacın son değişiklikten beri arttığını ya da azaldığını göstermek istiyorsunuz. count prop’u size bunu söylemez — prop’un bir önceki değeri hakkında bilgiyi siz takip etmelisiniz. prevCount state bileşenini önceki değerleri takip etmek için ekleyin. Sayacın arttığınımı yoksa azaldığınımı takip etmek için yeni bir trend state değişkeni ekleyin. prevCount ve count değerlerini kıyaslayın ve değeler eşit değilse,prevCount ve trend değerlerini güncelleyin. Şimdi mevcut sayaç prop’unu ve son render’dan itibaren nasıl değiştiğini gösterebilirsiniz.

import { useState } from 'react';

export default function CountLabel({ count }) {
  const [prevCount, setPrevCount] = useState(count);
  const [trend, setTrend] = useState(null);
  if (prevCount !== count) {
    setPrevCount(count);
    setTrend(count > prevCount ? 'artıyor' : 'azalıyor');
  }
  return (
    <>
      <h1>{count}</h1>
      {trend && <p>Sayaç {trend}</p>}
    </>
  );
}

Şunu unutmayın ki eğer set fonksiyonunu render esnasında çağırırsanız, bu fonksiyon prevCount !== count gibi bir koşullu ifadenin içinde olmak zorundadır ve koşullu ifadenin içinde setPrevCount(count) gibi bir çağrı olmak zorundadır. Aksi halde, bileşeniniz sonsuz bir döngü içinde çökene kadar yeniden render edilecektir. Aynı zamanda, şu anda render edilen bileşenin state’ini sadece bu şekilde güncelleyebilirsiniz.