Client-side data fetching

Kubilay
10 min readSep 9, 2022

--

Pre-rendering

Varsayılan olarak, Next.js her sayfayı önceden işler . Bu, Next.js’nin istemci tarafı JavaScript tarafından yapılması yerine her sayfa için önceden HTML oluşturduğu anlamına gelir. Ön işleme, daha iyi performans ve SEO ile sonuçlanabilir.

Oluşturulan her HTML, o sayfa için gerekli olan minimum JavaScript koduyla ilişkilendirilir. Bir sayfa tarayıcı tarafından yüklendiğinde, JavaScript kodu çalışır ve sayfayı tamamen etkileşimli hale getirir. (Bu işleme hidrasyon denir .)

Two forms of Pre-rendering

Next.js’nin iki ön işleme biçimi vardır: Statik Oluşturma ve Sunucu Tarafı İşleme . Fark, bir sayfa için HTML oluşturduğundadır.

Next.js , her sayfa için kullanmak istediğiniz ön işleme formunu seçmenize izin verir. Çoğu sayfa için Statik Oluşturma’yı ve diğerleri için Sunucu Tarafı İşleme’yi kullanarak bir “karma” Next.js uygulaması oluşturabilirsiniz.

Performans nedenleriyle Sunucu Tarafı Oluşturma yerine Statik Üretimi kullanmanızı öneririz . Statik olarak oluşturulmuş sayfalar, performansı artırmak için ekstra yapılandırma olmadan CDN tarafından önbelleğe alınabilir. Ancak bazı durumlarda Sunucu Tarafı Oluşturma tek seçenek olabilir. [Content Delivery Network (CDN) İçerik dağıtım ağı anlamına gelir]

Statik Üretim veya Sunucu Client-side Rendering (Tarafı İşleme ile birlikte İstemci Tarafı İşleme’yi) de kullanabilirsiniz . Bu, bir sayfanın bazı bölümlerinin tamamen istemci tarafı JavaScript tarafından oluşturulabileceği anlamına gelir.

Static Generation (Önerilen)

Bir sayfa Statik Üretim kullanıyorsa , sayfa HTML’si build time’da oluşturulur . Bu, next build,komutu çalıştırdığında sayfa HTML’sinin oluşturulduğu anlamına gelir . Bu HTML daha sonra her istekte yeniden kullanılacaktır. Bir CDN tarafından önbelleğe alınabilir

Static Generation with data

Bazı sayfalar, ön işleme için harici verilerin alınmasını gerektirir. İki senaryo vardır ve biri veya her ikisi de geçerli olabilir. Her durumda, Next.js’nin sağladığı şu işlevleri kullanabilirsiniz

  1. Sayfa içeriğiniz (content) harici verilere bağlıdır: getStaticProps.
  2. Sayfa içeriğiniz (content) path ile verilere bağlıdır getStaticPaths ve getStaticProps

Senaryo 1 : Sayfa içeriğiniz (content) harici verilere bağlıdır: getStaticProps.

Elimizde bir blog içeriği yönetme uygulaması olduğunu düşünelim. Ve ekteki gibi bir comp olsun .

function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
)
}

Pre-render aşamasında veriyi çekmek için NextJS async olan ve export edilmesi gereken bir fonksiyon kullanmamızı bekler.

// This function gets called at build time
export async function getStaticProps() {
// Call an external API endpoint to get posts
const res = await fetch('https://.../posts')
const posts = await res.json()
// By returning { props: { posts } }, the Blog component
// will receive `posts` as a prop at build time
return {
props: {
posts,
},
}
}
export default Blog

Senaryo 2 Sayfa içeriğiniz (content) path ile verilere bağlıdır.

Next.js, dinamik rotalara sahip sayfalar oluşturmanıza olanak tanır . Örneğin, pages/posts/[id].js gibi gibi

Dışarıdan gelecek olan veri bu id değerine bağlı olarak değişkenlik gösterecektir.
Elimizde www.kubilaybozak.com/posts/1 adında bir sayfamız olduğunu varsayalım bu sayfa için sadece linke tıklandığı zaman pre render olmasıını isteyelim.

Bu tarz durumlarda bizim sayfalarımız veriye bağlı olarak render edilir.
Bu gibi durumlar için Next.js, dinamik bir sayfadan (bahsedilen [post].js ) çağrılan async ve export edilmesi gereken getStaticPath isimli bir fonksiyon kullanır.

// This function gets called at build time
export async function getStaticPaths() {
// Call an external API endpoint to get posts
const res = await fetch('https://.../posts')
const posts = await res.json()
// Get the paths we want to pre-render based on posts
const paths = posts.map((post) => ({
params: { id: post.id },
}))
// We'll pre-render only these paths at build time.
// { fallback: false } means other routes should 404.
return { paths, fallback: false }
}

Yukarıda öncelikle postları çektik daha sonra map ile id’lere göre sayfalar oluşturmamız gerekiyor .

function Post({ post }) {
// Render post...
}
export async function getStaticPaths() {
// ...
}
// This also gets called at build time
export async function getStaticProps({ params }) {
// params contains the post `id`.
// If the route is like /posts/1, then params.id is 1
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
// Pass post data to the page via props
return { props: { post } }
}
export default Post

Daha sonra bu konuların detayına gireceğiz şimdi sıra Server Side Rendering kısmında.

Server Side Rendering

Bir sayfa Server-side Rendering, her istekte sayfa HTML’si oluşturulur .

Bir sayfa için Server-side Rendering kullanmak için adlı exportedilen asyncbir fonksiyon olan getServerSidePropfoksiyonuna ihtiyacınız vardır .Bu işlev, her istekte sunucu tarafından çağrılır.

Örneğin, sayfanızın sık güncellenen verileri (harici bir API’den alınan) önceden oluşturması gerektiğini varsayalım.

function Page({ data }) {
// Render data...
}
// This gets called on every request
export async function getServerSideProps() {
// Fetch data from external API
const res = await fetch(`https://.../data`)
const data = await res.json()
// Pass data to the page via props
return { props: { data } }
}
export default Page

Gördüğünüz gibi, getServerSideProps'e benzer getStaticProps, ancak fark, getServerSidePropsderleme zamanı yerine her istekte çalıştırılmasıdır.

/////////////////////////////////////////////////////////////////////

Server -Side-Rendering getServerSideProps(SSR)

Eğer bir sayfa sunucu tarafında oluşturulmak isteniyorsa kullanılması gereken fonksiyon.Next.js tarafından döndürülen verileri kullanarak her istekte bu sayfayı önceden oluşturur ve tarayıcı tarafına datalar ile beraber .

  • getServerSidePropsyalnızca sunucu tarafında çalışır ve hiçbir zaman tarayıcıda çalışmaz.
  • Bir sayfayı doğrudan request yollandığı zaman getServerSideProps istek zamanında çalışır ve return edilen propslara göre sayfa oluşturulur.
  • sadece page klasörü altında bulunan .js .jsx .tsx gibi dosyalarda kullanılabilir .
export async function getServerSideProps(context) {
return {
props: {}, // will be passed to the page component as props
}
}

Parametre olarak verilen context, aşağıdaki anahtarları içeren bir nesnedir:

  • params: Bu sayfa dinamik bir rota kullanıyorsa , paramsrota parametrelerini içerir. Sayfa adı ise [id].js, paramsşöyle görünecektir { id: ... }
  • query: Dinamik yol parametreleri dahil, sorgu dizesini temsil eden bir nesne.
  • localeetkin yerel ayarı içerir (etkinleştirilmişse).
  • localesdesteklenen tüm yerel ayarları içerir (etkinleştirilmişse).
  • defaultLocaleyapılandırılmış varsayılan yerel ayarı içerir (etkinleştirilmişse).

Return etmesi gereken değerler .

Mutlaka bir değer return etmesi gerekir genelde bu değerler dinamik olan değerler olur yukarıda bahsettiğimiz [1.js, 2.js 3.js gibi gibi ]

  • props, her değerin sayfa bileşeni tarafından alındığı bir anahtar/değer çiftidir mesela id vb. gibi datlar .
export async function getServerSideProps({ params }) {  
const resp = await fetch `https://Test.com/pokemon/${params.id}.json`
);
if (!pokemon) {
return null; }
return {
props: {
pokemon: await resp.json(),
},
};}
  • notFound ,Sayfanın olmaması bulunanmaması yada fetch işlemine çıkan bir hata sonucu 404 SayfanotFound döndürmesine izin verir .
export async function getServerSideProps(context) {
const res = await fetch(`https://.../data`)
const data = await res.json()
if (!data) {
return {
notFound: true,
}
}
return {
props: { data }, // will be passed to the page component as props
}
}
  • redirect, internal ve external kaynaklara yeniden yönlendirmeye izin verir. şekline uygun olmalıdır { destination: string, permanent: boolean }. HTTPBazı ender durumlarda, eski istemcilerin doğru şekilde yeniden yönlendirme yapması için özel bir durum kodu atamanız gerekebilir . Bu durumlarda, statusCodemülk yerine permanentmülkü kullanabilirsiniz, ancak ikisini birden kullanamazsınız.

getServerSideProps’u ne zaman kullanmalıyım?

Yalnızca, verileri istek zamanında alınması gereken bir sayfa oluşturmanız gerekiyorsa kullanmalısınız.
Basit bir örnek;

function Page({ data }) {
// Render data...
}
// This gets called on every request
export async function getServerSideProps() {
// Fetch data from external API
const res = await fetch(`https://.../data`)
const data = await res.json()
// Pass data to the page via props
return { props: { data } }
}
export default P
  • ****************************************************************

Static -Side-Generation getStaticProps (SSG)

Statik olarak oluşturduğumuz sayfaların derleme sırasında otomatik olarak oluşmasını istediğimiz zaman kullandığımı bir teknik.

export async function getStaticProps(context) {
return {
props: {}, // will be passed to the page component as props
}
}
  • paramsdinamik rotalar kullanan sayfalar için rota parametrelerini içerir . Örneğin, sayfa adı ise [id].jsşöyle paramsgörünecektir { id: ... }. getStaticPathsBuradan gelen bilgileri bu fonksiyonu bir sonraki konuda bahsedeceğiz.
  • previewtruesayfanın Önizleme Modunda olup olmadığı ve undefinedaksidir.
  • previewDatatarafından ayarlanan önizleme verilerini içerir setPreviewData.
  • localeetkin yerel ayarı içerir (etkinleştirilmişse).
  • localesdesteklenen tüm yerel ayarları içerir (etkinleştirilmişse).
  • defaultLocaleyapılandırılmış varsayılan yerel ayarı içerir (etkinleştirilmişse).

getStaticProps return değerleri

  • props, her değerin sayfa bileşeni tarafından alındığı bir anahtar/değer çiftidir.
export async function getStaticProps({ params }) {const resp = await fetch(`test.com/pokemon/${params.id}.json`);return {
props: {
pokemon: await resp.json()
},};}
  • revalidate, sayfanın yeniden oluşturulmasının gerçekleşebileceği saniye cinsinden miktardır (varsayılanı falseyeniden doğrulamadır veya yeniden doğrulama yoktur).
// This function gets called at build time on server-side.
// It may be called again, on a serverless function, if
// revalidation is enabled and a new request comes in
export async function getStaticProps() {
const res = await fetch('https://.../posts')
const posts = await res.json()
return {
props: {
posts,
},
// Next.js will attempt to re-generate the page:
// - When a request comes in
// - At most once every 10 seconds
revalidate: 10, // In seconds
}
}
  • notFound ,Sayfanın olmaması bulunanmaması yada fetch işlemine çıkan bir hata sonucu 404 SayfanotFound döndürmesine izin verir .
export async function getStaticProps(context) {
const res = await fetch(`https://.../data`)
const data = await res.json()
if (!data) {
return {
notFound: true,
}
}
return {
props: { data }, // will be passed to the page component as props
}
}
  • redirect, internal ve external kaynaklara yeniden yönlendirmeye izin verir. şekline uygun olmalıdır { destination: string, permanent: boolean }. HTTPBazı ender durumlarda, eski istemcilerin doğru şekilde yeniden yönlendirme yapması için özel bir durum kodu atamanız gerekebilir . Bu durumlarda, statusCodemülk yerine permanentmülkü kullanabilirsiniz, ancak ikisini birden kullanamazsınız.

getStaticPaths

Bir sayfanın Dinamik Rotaları (pokemon/[id].js gibi ) varsa ve kullanıyorsa getStaticProps, statik olarak oluşturulacak yolların bir listesini tanımlaması gerekir.
Next.js tarafından belirtilen tüm yolları statik olarak önceden işler

export async function getStaticPaths() {
return {
paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
fallback: false, // can also be true or 'blocking'
}
}

Basit bir önek kod .

// pages/posts/[id].js// Generates `/posts/1` and `/posts/2`
export async function getStaticPaths() {
return {
paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
fallback: false, // can also be true or 'blocking'
}
}
// `getStaticPaths` requires using `getStaticProps`
export async function getStaticProps(context) {
return {
// Passed to the page component as props
props: { post: {} },
}
}
export default function Post({ post }) {
// Render post...
}

getStaticPaths’i ne zaman kullanmalıyım?

Dinamik yolları kullanan getStaticPathssayfaları statik olarak önceden oluşturuyorsanız ve şunları kullanmalısınız:

  • Veriler headless CMS’den geliyor ise
  • Veriler bir veritabanından geliyor ise
  • Veriler dosya sisteminden geliyor ise
  • Veriler herkese açık olarak önbelleğe alınabiliyor ise (kullanıcıya özel değil)

getStaticPaths return değerleri

Örneğin, adında Dinamik Rotalar kullanan bir sayfanız olduğunu varsayalım pages/posts/[id].js.

  • paramsnesnenin değeri, sayfa adında kullanılan parametrelerle eşleşmelidir:
  • fallback

— 3 Farklı değer alır bu falback fonksiyonu.

False: Statik olarak oluşmayan sayfalar 404 hata mesajı döndürür. Sık sık yeni sayfalar eklenmiyor ise kullanışlı bir durumdur tam dersi durum için pek önerilmez. Eğer daha fazla yol eklenmesi gibi durumlar söz konusu olursa ve fallback değerinin false ise projenizi yeniden build etmeniz gerekecek.

True: uygulamanızın verilere bağlı çok sayıda statik sayfası varsa (çok büyük bir e-ticaret sitesi gibi) kullanışlıdır. Tüm ürün sayfalarını önceden oluşturmak istiyorsanız, derlemeler çok uzun zaman alacaktır.

Ek bilgiler :
getStaticPropseğer fallback: true ise kullanırken arka planda çalışır
getStaticPaths'i getServerSideProps ile kullanamazsınız.

return {
paths: [
{ params: { id: '1' }},
{
params: { id: '2' },
// with i18n configured the locale for the path can be returned as well
locale: "en",
},
],
fallback: ...
}

Regeneration (revalidate)

Basitçe [id].js olarak tanımlı bir site düşünelim bu sitede ekranda değişen veriler var ise bu verilerin ekrana yansıtmamız gerekiyor . Mesela bir döviz tablosu real time olarak değişem değerlere sahip bu gibi durumlarda server tarafından render alınan sayfaların yenilenmesi için gerekli olan durum.

Next.js, sitenizi oluşturduktan sonra statik sayfalar oluşturmanıza veya güncellemenize olanak tanır . Artımlı Statik Yenileme (ISR), sitenin tamamını yeniden oluşturmaya gerek kalmadan sayfa başına statik oluşturmayı kullanmanıza olanak tanır . ISR ile, milyonlarca sayfaya ölçeklerken statikin avantajlarını koruyabilirsiniz

function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
// This function gets called at build time on server-side.
// It may be called again, on a serverless function, if
// revalidation is enabled and a new request comes in
export async function getStaticProps() {
const res = await fetch('https://.../posts')
const posts = await res.json()
return {
props: {
posts,
},
// Next.js will attempt to re-generate the page:
// - When a request comes in
// - At most once every 10 seconds
revalidate: 10, // In seconds
}
}
// This function gets called at build time on server-side.
// It may be called again, on a serverless function, if
// the path has not been generated.
export async function getStaticPaths() {
const res = await fetch('https://.../posts')
const posts = await res.json()
// Get the paths we want to pre-render based on posts
const paths = posts.map((post) => ({
params: { id: post.id },
}))
// We'll pre-render only these paths at build time.
// { fallback: blocking } will server-render pages
// on-demand if the path doesn't exist.
return { paths, fallback: 'blocking' }
}
export default Blog

Oluşturma sırasında önceden oluşturulmuş bir sayfaya istek yapıldığında, başlangıçta önbelleğe alınmış sayfayı gösterecektir.

  • İlk istekten sonra ve 10 saniyeden önce sayfaya yapılan tüm istekler de önbelleğe alınır ve anında gerçekleşir.
  • 10 saniyelik pencereden sonra, bir sonraki istek önbelleğe alınmış (eski) sayfayı göstermeye devam edecektir.
  • Next.js, arka planda sayfanın yenilenmesini tetikler.
  • Sayfa başarıyla oluşturulduktan sonra, Next.js önbelleği geçersiz kılar ve güncellenen sayfayı gösterir. Arka plan yenileme başarısız olursa, eski sayfa değişmeden kalır.

Next.js, belirli bir sayfa için Next.js önbelleğini manuel olarak temizlemek için İsteğe Bağlı Artımlı Statik Yenilemeyi destekler. Bu, aşağıdaki durumlarda sitenizi güncellemeyi kolaylaştırır:

  • Başsız CMS’nizden içerik oluşturulur veya güncellenir
  • E-ticaret meta veri değişiklikleri (fiyat, açıklama, kategori, incelemeler vb.)

Client-side Rendering

İstemci tarafı veri alma, sayfanız SEO indekslemesi gerektirmediğinde, verilerinizi önceden oluşturmanız gerekmediğinde veya sayfalarınızın içeriğinin sık sık güncellenmesi gerektiğinde kullanışlıdır. Sunucu tarafı işleme API’lerinden farklı olarak, bileşen düzeyinde istemci tarafı veri getirmeyi kullanabilirsiniz.

Sayfa düzeyinde yapılırsa, veriler çalışma zamanında getirilir ve veriler değiştikçe sayfanın içeriği güncellenir. Bileşen düzeyinde kullanıldığında, veriler bileşen montajı sırasında alınır ve bileşenin içeriği, veriler değiştikçe güncellenir.

İstemci tarafında veri getirmeyi kullanmanın, uygulamanızın performansını ve sayfalarınızın yüklenme hızını etkileyebileceğini unutmamak önemlidir. Bunun nedeni, veri alma işleminin bileşen veya sayfalar monte edildiğinde yapılması ve verilerin önbelleğe alınmamasıdır.

function Profile() {
const [data, setData] = useState(null)
const [isLoading, setLoading] = useState(false)
useEffect(() => {
setLoading(true)
fetch('/api/profile-data')
.then((res) => res.json())
.then((data) => {
setData(data)
setLoading(false)
})
}, [])
if (isLoading) return <p>Loading...</p>
if (!data) return <p>No profile data</p>
return (
<div>
<h1>{data.name}</h1>
<p>{data.bio}</p>
</div>
)
}

--

--

No responses yet