Published

React 18 ile Gelen Yeni Özellikler

Yazar
  • avatar
    İsim
    Elif Nur Karakoç

Bu blog yazısında Kasım ayında Beta sürümü yayınlanan React 18‘in özelliklerine değineceğim :)

React 18 Beta sürümünü kurmak için kullanılan komut:

yarn add react@beta react-dom@beta

React 18, client-side ve server-side ‘da değişiklikler getirmektedir.

React 18 ile gelen özellikler:

  • New Root API

  • Automatic batching

  • Suspense

  • SuspenseList

  • startTransition, useTransition hook

  • useDeferredValue

  • SSR concurrency

New Root API vs Legacy Root API

React uygulamaları, uygulamanın root elementi, DOM’a eklenerek oluşturulur.

Legacy Root API, ReactDom.render() ile çağrılan mevcut API'dır. React 17'deki gibi çalışan bir uygulama oluşturur.

Kod örneği:

import React from  "react";
import ReactDOM from  "react-dom";
import App from  "./App";

ReactDOM.render(<App />, document.getElementById("root"));

New Root API, ReactDOM.createRoot() ile çağrılmaktadır. render, createRoot ile yer değiştirmiştir. hydrate, hydrateRoot ile yer değiştirmiştir. React 18’de bulunan özellikleri kullanabilmek için geliştirme yapılan projeyi React 18’e yükseltmek ve yeni Root API kullanılması gerekmektedir.

Kod örneği:

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";

const rootElement = document.getElementById("root");
const root = ReactDOM.createRoot(rootElement);
root.render(<App />);

Bu değişikliğin geçişinin kolay olması ve kullanıcıların deneyimlemesi için React 18'de iki API'da kullanılabilmektedir.

Automatic Batching

Batching, React'ın daha iyi performans için birden çok state güncellemesini tek bir yeniden oluşturma (a single re-render) sırasında gruplamasıdır. Gereksiz UI re-renderların önlenmesi React 17’de event handler da yapıldı. React 18'de createRoot ile tüm state güncellemeleri otomatik olarak gruplandırılmaktadır.

Kod Örneği (kod kaynağı) :

function App() {
    const [count, setCount] = useState(0);
    const [flag, setFlag] = useState(false);

    function handleClick() {
    setCount(c => c + 1); // Does not re-render yet
    setFlag(f => !f); // Does not re-render yet
    // React will only re-render once at the end (that's batching!)
    }

    return (
    <div>
        <button onClick={handleClick}>Next</button>
        <h1 style={{ color: flag ? "blue" : "black" }}>{count}</h1>
    </div>
    );
}

count state'i güncellenir, re-render gerçekleşmez, flag state'i güncellenir. count ve flag aynı anda re-render edilir. UI'da count ve flag'i aynı anda değişir.

React17 ve React 18 karşılaştırması için örnekleri inceleyebilirsin.

createRoot kullanılıyorsa ve state güncellemesinin hemen gerçekleşmesi gerekiyor ise flushSync() kullanılmaktadır. flushSync() batching'den çıkmayı sağlamaktadır.

Kod örneği (kod kaynağı):

import { flushSync } from 'react-dom'; // Note: react-dom, not react

function handleClick() {
    flushSync(() => {
    setCounter(c => c + 1);
    });
    // React has updated the DOM by now
    flushSync(() => {
    setFlag(f => !f);
    });
    // React has updated the DOM by now
}

Suspense

Suspense, componentlerin oluşturulmadan önce bir şey için "beklemesini" (örneğin asenkron işlemler ) sağlar ve beklerken bir geri dönüş gösterir. Kod örneği (kod kaynağı) :

<Suspense fallback={<h1>Loading...</h1>}>
    <ProfilePhoto />
    <ProfileDetails />
</Suspense>

ProfileDetails, bazı verileri almak için asenkron bir API call bekliyor. ProfileDetails ve ProfilePhoto'yu beklerken Loading... gösterilir. fallback: Suspense componentinin, children componentlerinin oluşturulması bitene kadar UI'da gösterilir.

SuspenseList

<SuspenseList revealOrder="forwards">
    <Suspense fallback={'Loading...'}>
    <ProfilePicture id={1} />
    </Suspense>
    <Suspense fallback={'Loading...'}>
    <ProfilePicture id={2} />
    </Suspense>
    <Suspense fallback={'Loading...'}>
    <ProfilePicture id={3} />
    </Suspense>
    ...
</SuspenseList>

(Kod kaynağı)

SuspenseList, kullanıcıya gösterilcek componentlerin gösterilme sırasını düzenler, componenetleri koordine etmeye yardımcı olur. Birden çok componentin veri alması gerektiğinde, bu veriler öngörülemeyen bir sırada gelebilir. Componentleri bir SuspenseList içine yazarsak, önceki componentler görüntülenene kadar React, component göstermez.

SuspenseList iki prop almaktadır:

  • revealOrder (forwards, backwards, together): SuspenseList children componentlerinin ortaya çıkma sırasını tanımlar.
  • tail (collapsed, hidden): SuspenseList'te boşaltılan componentlerin nasıl gösterileceğini belirler. SuspenseList, default olarak tüm fallbackler'i göstermekte, collapsed sadece sonraki fallback'i göstermektedir. hidden yüklenmemiş herhangi bir öğeyi göstermez.

startTransition

Kod örneği (kod kaynağı):

// Show what you typed
setInputValue(input);

// Show the results
setTimeout(() => {
    setSearchQuery(input);
}, 0);

Input alanından alınan değer inputValue state'ne set edilir. setSearchQuery ile girilen değere göre arama sorgusu yapar ve UI güncellenir. setSearchQuery render edilmesi uzun sürerse, UI güncellemesinde gecikme meydana gelir. setTimeout ile gecikmenin önüne geçiyoruz.

React 18'de bunun için startTransition kullanılmaktadır.

State güncellemeleri iki kategoriye ayrılmaktadır.

  • Urgent updates: tıklama, yazma gibi doğrudan etkileşim yansıtılır.
  • Transition updates: kullanıcı arayüzü bir görünümden diğerine geçirilir.

Kod örneği (kod kaynağı) :

import { startTransition } from 'react';

// Urgent: Show what was typed
setInputValue(input);

// Mark any state updates inside as transitions
startTransition(() => {
    // Transition: Show the results
    setSearchQuery(input);
});

Bekleyen geçişi göstermemizi de useTransition() hook'u sağlamaktadır.

import { useTransition } from 'react';

const [isPending, startTransition] = useTransition();

{isPending && <Spinner />}

Detaylı örnek için bu linki inceleyebilirsin.

useDeferredValue

useDeferredValue hook'u sayfa yüklenmeye devam ederken, UI'ın belli bir bölümünün, bir süreye kadar güncellenmesini ertelememizi sağlamaktadır.

Kod örneği (kod kaynağı) :

function App() {
    const [text, setText] = useState("hello");
    const deferredText = useDeferredValue(text, { timeoutMs: 2000 });

    return (
    <div className="App">
        {/* Keep passing the current text to the input */}
        <input value={text} onChange={handleChange} />
        ...
        {/* But the list is allowed to "lag behind" when necessary */}
        <MySlowList text={deferredText} />
    </div>
    );
    }

text hemen gösterilir. MySlowList 2 saniye sonra render edilir.

useDeferredValue, startTransition ve useTransition ile birlikte kullanılabilir.

SSR Concurrency

Suspense, server-side rendering'i desteklemiyordu. React 18 ile değişti.

  • renderToString: Hala çalışıyor, ancak sınırlı Suspense desteğiyle ile çalışmaktadır.
  • renderToNodeStream: kullanımdan kaldırıldı.
  • pipeToNodeWritable: yeni, ve tavsiye edilmekte. Suspense desteği var.

Okuduğun için teşekkürler. Yeni bir yazıda görüşmek üzere, iyi çalışmalar :)

Kaynakça

https://github.com/reactwg/react-18/discussions/112

https://github.com/reactwg/react-18/discussions/5

https://github.com/reactwg/react-18/discussions/21

https://github.com/reactwg/react-18/discussions/37

https://github.com/reactwg/react-18/discussions/41

https://github.com/reactwg/react-18/discussions/65

https://reactjs.org/docs/concurrent-mode-reference.html