Sağlam ve öngörülebilir kullanıcı arayüzleri oluşturmak için React'in useActionState hook'unu durum makineleriyle keşfedin. Karmaşık uygulamalar için eylem durumu geçiş mantığını öğrenin.
React useActionState Durum Makinesi: Eylem Durumu Geçiş Mantığında Uzmanlaşma
React'in useActionState
'i, özellikle sunucu eylemleriyle uğraşırken asenkron durum güncellemelerini basitleştirmek için tasarlanmış, React 19'da (şu anda canary sürümünde) sunulan güçlü bir hook'tur. Bir durum makinesiyle birleştirildiğinde, karmaşık kullanıcı arayüzü etkileşimlerini ve durum geçişlerini yönetmek için zarif ve sağlam bir yol sunar. Bu blog yazısı, öngörülebilir ve sürdürülebilir React uygulamaları oluşturmak için useActionState
'i bir durum makinesiyle nasıl etkili bir şekilde kullanacağımızı derinlemesine inceleyecektir.
Durum Makinesi Nedir?
Bir durum makinesi, bir sistemin davranışını sonlu sayıda durum ve bu durumlar arasındaki geçişler olarak tanımlayan bir hesaplama matematik modelidir. Her durum, sistemin belirli bir koşulunu temsil eder ve geçişler, sistemin bir durumdan diğerine geçmesine neden olan olayları temsil eder. Bunu bir akış şeması gibi düşünebilirsiniz, ancak adımlar arasında nasıl hareket edebileceğinize dair daha katı kuralları vardır.
React uygulamanızda bir durum makinesi kullanmak birçok fayda sağlar:
- Öngörülebilirlik: Durum makineleri, uygulamanızın davranışı hakkında akıl yürütmeyi kolaylaştıran açık ve öngörülebilir bir kontrol akışı sağlar.
- Sürdürülebilirlik: Durum mantığını kullanıcı arayüzü oluşturmadan ayırarak, durum makineleri kod organizasyonunu geliştirir ve uygulamanızı sürdürmeyi ve güncellemeyi kolaylaştırır.
- Test Edilebilirlik: Her durum ve geçiş için beklenen davranışı kolayca tanımlayabildiğiniz için durum makineleri doğası gereği test edilebilirdir.
- Görsel Temsil: Durum makineleri görsel olarak temsil edilebilir, bu da uygulamanın davranışını diğer geliştiricilere veya paydaşlara iletmede yardımcı olur.
useActionState
'e Giriş
useActionState
hook'u, potansiyel olarak uygulama durumunu değiştiren bir eylemin sonucunu yönetmenize olanak tanır. Sunucu eylemleriyle sorunsuz çalışacak şekilde tasarlanmıştır, ancak istemci tarafı eylemleri için de uyarlanabilir. Yükleme durumlarını, hataları ve bir eylemin nihai sonucunu yönetmek için temiz bir yol sunarak duyarlı ve kullanıcı dostu arayüzler oluşturmayı kolaylaştırır.
İşte useActionState
'in nasıl kullanıldığına dair temel bir örnek:
const [state, dispatch] = useActionState(async (prevState, formData) => {
// Eylem mantığınız buraya gelecek
try {
const result = await someAsyncFunction(formData);
return { ...prevState, data: result };
} catch (error) {
return { ...prevState, error: error.message };
}
}, { data: null, error: null });
Bu örnekte:
- İlk argüman, eylemi gerçekleştiren asenkron bir fonksiyondur. Önceki durumu ve form verilerini (varsa) alır.
- İkinci argüman başlangıç durumudur.
- Hook, mevcut durumu ve bir dispatch fonksiyonunu içeren bir dizi döndürür.
useActionState
ve Durum Makinelerini Birleştirmek
Asıl güç, useActionState
'i bir durum makinesiyle birleştirmekten gelir. Bu, asenkron eylemlerle tetiklenen karmaşık durum geçişlerini tanımlamanıza olanak tanır. Bir senaryo düşünelim: ürün ayrıntılarını getiren basit bir e-ticaret bileşeni.
Örnek: Ürün Detaylarını Getirme
Ürün detayları bileşenimiz için aşağıdaki durumları tanımlayacağız:
- Boşta (Idle): Başlangıç durumu. Henüz hiçbir ürün detayı getirilmedi.
- Yükleniyor (Loading): Ürün detayları getirilirkenki durum.
- Başarılı (Success): Ürün detayları başarıyla getirildikten sonraki durum.
- Hata (Error): Ürün detayları getirilirken bir hata oluşması durumundaki durum.
Bu durum makinesini bir nesne kullanarak temsil edebiliriz:
const productDetailsMachine = {
initial: 'idle',
states: {
idle: {
on: {
FETCH: 'loading',
},
},
loading: {
on: {
SUCCESS: 'success',
ERROR: 'error',
},
},
success: {
type: 'final',
},
error: {
on: {
FETCH: 'loading',
},
},
},
};
Bu basitleştirilmiş bir gösterimdir; XState gibi kütüphaneler hiyerarşik durumlar, paralel durumlar ve korumalar gibi özelliklerle daha gelişmiş durum makinesi uygulamaları sunar.
React Uygulaması
Şimdi, bu durum makinesini bir React bileşeninde useActionState
ile entegre edelim.
import React from 'react';
// Tam durum makinesi deneyimi istiyorsanız XState'i yükleyin. Bu temel örnek için basit bir nesne kullanacağız.
// import { createMachine, useMachine } from 'xstate';
const productDetailsMachine = {
initial: 'idle',
states: {
idle: {
on: {
FETCH: 'loading',
},
},
loading: {
on: {
SUCCESS: 'success',
ERROR: 'error',
},
},
success: {
type: 'final',
},
error: {
on: {
FETCH: 'loading',
},
},
},
};
function ProductDetails({ productId }) {
const [state, dispatch] = React.useReducer(
(state, event) => {
const nextState = productDetailsMachine.states[state].on[event];
return nextState || state; // Geçiş tanımlanmamışsa sonraki durumu veya mevcut durumu döndür
},
productDetailsMachine.initial
);
const [productData, setProductData] = React.useState(null);
const [error, setError] = React.useState(null);
React.useEffect(() => {
if (state === 'loading') {
const fetchData = async () => {
try {
const response = await fetch(`https://api.example.com/products/${productId}`); // Kendi API uç noktanızla değiştirin
if (!response.ok) {
throw new Error(`HTTP hatası! durum: ${response.status}`);
}
const data = await response.json();
setProductData(data);
setError(null);
dispatch('SUCCESS');
} catch (e) {
setError(e.message);
setProductData(null);
dispatch('ERROR');
}
};
fetchData();
}
}, [state, productId, dispatch]);
const handleFetch = () => {
dispatch('FETCH');
};
return (
Ürün Detayları
{state === 'idle' && }
{state === 'loading' && Yükleniyor...
}
{state === 'success' && (
{productData.name}
{productData.description}
Fiyat: ${productData.price}
)}
{state === 'error' && Hata: {error}
}
);
}
export default ProductDetails;
Açıklama:
productDetailsMachine
'i durum makinemizi temsil eden basit bir JavaScript nesnesi olarak tanımlıyoruz.- Makinemize dayalı durum geçişlerini yönetmek için
React.useReducer
kullanıyoruz. - Durum 'loading' olduğunda veri getirmeyi tetiklemek için React'in
useEffect
hook'unu kullanıyoruz. handleFetch
fonksiyonu 'FETCH' olayını göndererek yükleme durumunu başlatır.- Bileşen, mevcut duruma göre farklı içerikler oluşturur.
useActionState
Kullanımı (Varsayımsal - React 19 Özelliği)
useActionState
henüz tam olarak mevcut olmasa da, kullanılabilir olduğunda uygulamanın nasıl görüneceğine dair daha temiz bir yaklaşım sunan bir örnek aşağıdadır:
import React from 'react';
//import { useActionState } from 'react'; // Kullanılabilir olduğunda yorum satırını kaldırın
const productDetailsMachine = {
initial: 'idle',
states: {
idle: {
on: {
FETCH: 'loading',
},
},
loading: {
on: {
SUCCESS: 'success',
ERROR: 'error',
},
},
success: {
type: 'final',
},
error: {
on: {
FETCH: 'loading',
},
},
},
};
function ProductDetails({ productId }) {
const initialState = { state: productDetailsMachine.initial, data: null, error: null };
// Varsayımsal useActionState uygulaması
const [newState, dispatch] = React.useReducer(
(state, event) => {
const nextState = productDetailsMachine.states[state.state].on[event];
return nextState ? { ...state, state: nextState } : state; // Geçiş tanımlanmamışsa sonraki durumu veya mevcut durumu döndür
},
initialState
);
const handleFetchProduct = async () => {
dispatch('FETCH');
try {
const response = await fetch(`https://api.example.com/products/${productId}`); // Kendi API uç noktanızla değiştirin
if (!response.ok) {
throw new Error(`HTTP hatası! durum: ${response.status}`);
}
const data = await response.json();
// Başarıyla getirildi - verilerle birlikte SUCCESS olayını gönderin!
dispatch('SUCCESS');
// Getirilen veriyi yerel duruma kaydet. Reducer içinde dispatch kullanılamaz.
newState.data = data; // Dispatcher dışında güncelle
} catch (error) {
// Hata oluştu - hata mesajıyla birlikte ERROR olayını gönderin!
dispatch('ERROR');
// Hatayı render() içinde gösterilecek yeni bir değişkende sakla
newState.error = error.message;
}
//}, initialState);
};
return (
Ürün Detayları
{newState.state === 'idle' && }
{newState.state === 'loading' && Yükleniyor...
}
{newState.state === 'success' && newState.data && (
{newState.data.name}
{newState.data.description}
Fiyat: ${newState.data.price}
)}
{newState.state === 'error' && newState.error && Hata: {newState.error}
}
);
}
export default ProductDetails;
Önemli Not: Bu örnek varsayımsaldır çünkü useActionState
henüz tam olarak mevcut değildir ve kesin API'si değişebilir. Çekirdek mantığın çalışması için onu standart useReducer ile değiştirdim. Ancak, niyet, kullanılabilir hale geldiğinde ve useReducer'ı useActionState ile değiştirmeniz gerektiğinde onu nasıl kullanacağınızı göstermektir. Gelecekte useActionState
ile bu kod, asenkron veri yönetimini büyük ölçüde basitleştirerek, minimum değişiklikle açıklandığı gibi çalışmalıdır.
useActionState
'i Durum Makineleriyle Kullanmanın Faydaları
- Sorumlulukların Net Bir Şekilde Ayrılması: Durum mantığı durum makinesi içinde kapsüllenirken, kullanıcı arayüzü oluşturma React bileşeni tarafından yönetilir.
- Geliştirilmiş Kod Okunabilirliği: Durum makinesi, uygulamanın davranışının görsel bir temsilini sunarak anlaşılmasını ve sürdürülmesini kolaylaştırır.
- Basitleştirilmiş Asenkron Yönetim:
useActionState
, asenkron eylemlerin yönetimini kolaylaştırarak standart kod miktarını azaltır. - Gelişmiş Test Edilebilirlik: Durum makineleri doğası gereği test edilebilirdir, bu da uygulamanızın davranışının doğruluğunu kolayca doğrulamanıza olanak tanır.
İleri Düzey Kavramlar ve Dikkat Edilmesi Gerekenler
XState Entegrasyonu
Daha karmaşık durum yönetimi ihtiyaçları için XState gibi özel bir durum makinesi kütüphanesi kullanmayı düşünün. XState, hiyerarşik durumlar, paralel durumlar, korumalar ve eylemler gibi özelliklerle durum makinelerini tanımlamak ve yönetmek için güçlü ve esnek bir çerçeve sunar.
// XState kullanan örnek
import { createMachine, useMachine } from 'xstate';
const productDetailsMachine = createMachine({
id: 'productDetails',
initial: 'idle',
states: {
idle: {
on: {
FETCH: 'loading',
},
},
loading: {
invoke: {
id: 'fetchProduct',
src: (context, event) => fetch(`https://api.example.com/products/${context.productId}`).then(res => res.json()),
onDone: {
target: 'success',
actions: assign({ product: (context, event) => event.data })
},
onError: {
target: 'error',
actions: assign({ error: (context, event) => event.data })
}
}
},
success: {
type: 'final',
},
error: {
on: {
FETCH: 'loading',
},
},
},
}, {
services: {
fetchProduct: (context, event) => fetch(`https://api.example.com/products/${context.productId}`).then(res => res.json())
}
});
Bu, durumu yönetmek için daha bildirimsel ve sağlam bir yol sağlar. Kurulum için: npm install xstate
komutunu kullandığınızdan emin olun.
Global Durum Yönetimi
Birden çok bileşen arasında karmaşık durum yönetimi gereksinimleri olan uygulamalar için, durum makineleriyle birlikte Redux veya Zustand gibi global bir durum yönetimi çözümü kullanmayı düşünün. Bu, uygulamanızın durumunu merkezileştirmenize ve bileşenler arasında kolayca paylaşmanıza olanak tanır.
Durum Makinelerini Test Etme
Durum makinelerini test etmek, uygulamanızın doğruluğunu ve güvenilirliğini sağlamak için çok önemlidir. Durum makineleriniz için birim testleri yazmak, durumlar arasında beklendiği gibi geçiş yaptıklarını ve farklı olayları doğru şekilde yönettiklerini doğrulamak için Jest veya Mocha gibi test çerçevelerini kullanabilirsiniz.
İşte basit bir örnek:
// Örnek Jest testi
import { interpret } from 'xstate';
import { productDetailsMachine } from './productDetailsMachine';
describe('productDetailsMachine', () => {
it('should transition from idle to loading on FETCH event', (done) => {
const service = interpret(productDetailsMachine).onTransition((state) => {
if (state.value === 'loading') {
expect(state.value).toBe('loading');
done();
}
});
service.start();
service.send('FETCH');
});
});
Uluslararasılaştırma (i18n)
Küresel bir kitle için uygulamalar oluştururken, uluslararasılaştırma (i18n) esastır. Durum makinesi mantığınızın ve kullanıcı arayüzü oluşturmanızın birden çok dili ve kültürel bağlamı desteklemek için uygun şekilde uluslararasılaştırıldığından emin olun. Aşağıdakileri göz önünde bulundurun:
- Metin İçeriği: Kullanıcının yerel ayarına göre metin içeriğini çevirmek için i18n kütüphaneleri kullanın.
- Tarih ve Saat Formatları: Tarihleri ve saatleri kullanıcının bölgesine uygun formatta görüntülemek için yerel ayara duyarlı tarih ve saat biçimlendirme kütüphaneleri kullanın.
- Para Birimi Formatları: Para birimi değerlerini kullanıcının bölgesine uygun formatta görüntülemek için yerel ayara duyarlı para birimi biçimlendirme kütüphaneleri kullanın.
- Sayı Formatları: Sayıları kullanıcının bölgesine uygun formatta (örneğin, ondalık ayırıcılar, binlik ayırıcılar) görüntülemek için yerel ayara duyarlı sayı biçimlendirme kütüphaneleri kullanın.
- Sağdan Sola (RTL) Düzen: Arapça ve İbranice gibi diller için RTL düzenlerini destekleyin.
Bu i18n yönlerini göz önünde bulundurarak, uygulamanızın küresel bir kitle için erişilebilir ve kullanıcı dostu olmasını sağlayabilirsiniz.
Sonuç
React'in useActionState
'ini durum makineleriyle birleştirmek, sağlam ve öngörülebilir kullanıcı arayüzleri oluşturmak için güçlü bir yaklaşım sunar. Durum mantığını kullanıcı arayüzü oluşturmadan ayırarak ve net bir kontrol akışı uygulayarak, durum makineleri kod organizasyonunu, sürdürülebilirliği ve test edilebilirliği artırır. useActionState
henüz gelecek bir özellik olsa da, durum makinelerini şimdi nasıl entegre edeceğinizi anlamak, kullanılabilir olduğunda faydalarından yararlanmaya hazırlanmanızı sağlayacaktır. XState gibi kütüphaneler, karmaşık uygulama mantığını yönetmeyi kolaylaştıran daha da gelişmiş durum yönetimi yetenekleri sunar.
Durum makinelerini ve useActionState
'i benimseyerek, React geliştirme becerilerinizi yükseltebilir ve dünya çapındaki kullanıcılar için daha güvenilir, sürdürülebilir ve kullanıcı dostu uygulamalar oluşturabilirsiniz.