Skip to content

React Dersleri

EmirhanPala edited this page Dec 11, 2022 · 1 revision

Bölüm1: Temel JS Çalışmak

  • React Nedir? Ne Zaman İhtiyaç Duyarız?
  • Real Dom / Virtual Dom
Real Dom / Virtual Dom HK.
REAL DOM (GERÇEK DOM) KAVRAMLARI:
-Bir web sayfasına girdiğimizde Dev Tool(Öğeyi Denetle) açtığımızda görünen hiyerarşik "HTML" etiketlerinin bütününe "REAL DOM" deniyor.

VİRTUAL DOM (SANAL DOM) KAVRAMLARI:
-REAL DOM'un bir kopyası aynısı sadece bu react tarafında bir js objesi olarak tutuluyor.

---Yaptığı Nedir?
-Ekranımızda bir güncelleme işlemi olduğu anda (Bir veri güncellenecekse) "React" gidip. Virtual Dom'u ve Real Dom'u karşılaştırıyor. Eğer bunların arasında bir fark varsa (sadece farklı olan kısmı getirip) Real Dom'a yazıyor.

---Peki bunu yapmasının sebebi nedir?
Gereksiz RENDER'in önüne geçmek. Aynı zamanda (Sadece güncellenmesi gereken alanların güncellenmesini sağlıyabilmek) O yüzden Real Dom'un bir klonu React tarafında (JS Objesi) olarak tutuluyor. Bir güncelleme işlemi olduğu anda React'ın kendi içindeki farklılık algoritmaları çalıştırılıyor. Eğer bir farklılık varsa o farklılık getirilip Real Dom'a yansıtılıyor.
  • IDE / Text Editör Seçimi
  • Node.JS Kurulumu
  • Temel Node.JS
  • ES6 Modül Sistemi
ES6 Modül Sistemi HK.
-JavaScriptin bir önceki versiyonunda yapamayıp ta artık yapabildiğimiz bir takım işlemler var. (Yeni keywordler var)
Örnek:
-ES6 dan önce yapılan import işlemi
var slugify = require("slugify");
-Artık bunu yaparken import ifadesini(keyword) kullanabiliyoruz.
Örnek:
package.json dosyamızda "type": "module" tanımını yapmamız gerekecek ve sonrasında
import slugify from "slugify"; olarak kullanabiliriz.
/*
Terminalden
npm install slugify
Yazıp projeme kütüphaneyi ekliyorum.
*/

//İndirmiş olduğumuz modülü projemize dahil edelim.
//www.npmjs.com buradan modüller bulunabilir.
//Slugify bulup örnek kodları çalıştırıyorum.
import slugify from "slugify";
//const title = slugify("some string");
//console.log(title);
//Terminal üstünden npm start yazıp test ediyorum.

/*
Terminal Çıktısı:
> [email protected] start
> node index
some-string
*/

//İkinci parametredede otomatik tanımladığı - yerine artık boşluk bulduğu yerlere * yazıcak.
//const title = slugify("some string lorem ipsum", "*");
//console.log(title);

/*
Terminal Çıktısı:
> [email protected] start
> node index
some*string*lorem*ipsum
*/

//npm ile modül indirip kurmak bu şekilde!
  • Callback Functions / async-await ve Axios
/*
Javascript'in direk kendinde olan bir kaç fonksiyon var.
*/

/*
Bu fonksiyonun yaptığı işlem verilen parametredeki süre tamamlandıktan sonra bir kere çalışıyor olması.
2 Parametre istiyor bizden. 1'de fonksiyon olacak 2'de milisaniye cinsinden değer girmemizi isteyecek.
Örnek:
*/
setTimeout(() => {
    console.log("Merhaba");
}, 2000);
/*
Terminal Çıktısı: node callback.js
2 Saniye sonra ekrana alttaki kelimeyi yazıyor.
Merhaba
*/

//Bir diğeri setInterval bu fonksiyonda benzer şekilde parametrelerini alıyor.
setInterval(() => {
    console.log("Merhaba ben her saniye çalışacağım.");
}, 1000);
//1000 ms = 1 Saniye 
//İntervalde yapılan şey verilen parametrede her periyodda çalışıyor olması durdurulmazsa sonsuza kadar çalıştırılır.
/*
Terminal Çıktısı: node callback.js
Her saniye alttaki kelimeyi yazıyor.
Merhaba ben her saniye çalışacağım.
Merhaba ben her saniye çalışacağım.
Merhaba ben her saniye çalışacağım.
Merhaba ben her saniye çalışacağım.
*/

const sayiHi = () => {
  console.log("Merhaba");
};
merhabaDe();
/*
Terminal Çıktısı: node callback.js
Merhaba
*/

//Parametre göndericez o parametre bir fonksiyon olacak ve o fonksiyonu buradan alıp kullanamaya çalışıcaz.
const sayiHi = (cb) => { //Burda bir callback parametresi alırsak ve o callback'i 
    cb(); //böyle kullanırsak
};
sayiHi(() => {//Parametre olarak fonksiyon göndermiştik işte o fonksiyon cb ye düşüyor. ve yukarda cb(); olarak çalıştırıyoruz.
    console.log("Hello");
})
/* Yine yukardaki gibi aynı şekilde çalışmaya devam ediyor.
Terminal Çıktısı: node callback.js
Hello

Napmış olduk?
Parametre olarak bir fonksiyon geçtik ve onu ilgili fonksiyon içerisinde çalıştırmayı sağladık.
Peki bu bizim ne işimize yarayacak ?
*/

/*
Adım 3:
Javascript'te her hangi bir veri kaynağına gidip veri çekebilmek için bize verilmiş olan native(yerli) fonksiyon var.
ismi fetch bu gidiyor her hangi bir veri kaynağına bağlanıyor. Her hangi bir end point'i oradan veriyi alıp bize gösteriyor.
Örnek Bulalım: 
jsonplaceholder.typicode.com
Burada bize verilmiş bir end point var. Deneme yapmak amaçlı Bir json çıktı dönüyor bize
Ve biz bu içeriğe erişmeye çalışıcaz nodejs projemiz aracılığıyla.

Örnek:
Yazdığımız kodu kullanabilmemiz için node-fetch kurmamız gerekiyor.
Terminale: "npm i node-fetch" yazıp modülü yüklüyoruz.
*/

import fetch from "node-fetch";

fetch("https://jsonplaceholder.typicode.com/users") //Api'den bize data döndükten, (response döndükten) sonra 
    .then((data) => data.json()) //(data)'ya apiden ne geliyorsa o getiriliyor. Sonra bu native fetch kütüphanesi bize doğrudan json dönmüyor.
    //data.json() olarak onu json'a parse etmemiz gerekiyor. Ve bize bir data dönüyor.
    .then((users) => console.log(users));//Data burdaki (users)'a düşüyor. Bizde oradan alıp kullanmaya devam ediyoruz.
//fetch işlemi bu şekilde yapılıyor.

//Yeni bir işlem daha yapalım.
fetch("https://jsonplaceholder.typicode.com/users")
    .then((data) => data.json())
    .then((users) => { //Bu içerde yani callback'de yeni bir fetch işlemi yapalım.
        console.log("Users Yüklendi!", users)
        fetch("https://jsonplaceholder.typicode.com/posts/1")//Tekrardan fetch işlemi yapıyoruz.
            .then((data) => data.json())
            .then((posts) => console.log("Postlar Yüklendi!", posts));
        //Burada diyoruzki ilk işlem bitsin users'ları çeksin ve o işlem bittikten sonra bu olsun dediğimiz için bu then'in içinden yazıyoruz.
    });
//Önce userlar sonra postslar yüklenecek.
//Bu işlemi dışarda yapıcak olsaydık.

//Bunların ikiside asenkron olduğu için yani bunların ne zaman cevap döneceğini bilmiyoruz.
fetch("https://jsonplaceholder.typicode.com/users")//1. Belki bu 1 saniyede dönüyor
    .then((data) => data.json())
    .then((users) => {//5. Veya buradaki users'ın içindeki dataya bağlı olabiliriz.
        console.log("Users Yüklendi!", users)//3. Ama biz önce bu logu görmek istiyor olabiliriz.
    });
fetch("https://jsonplaceholder.typicode.com/posts/1")//2. Bu yarım saniyede dönüyor olabilir.
    .then((data) => data.json())
    .then((posts) => console.log("Postlar Yüklendi!", posts));//4. Sonra bu logu görmek istiyor olabiliriz.
//6. O yüzden bu işlemleri sıraya koymamız gerekiyor olabilir.
//Bu kodu çalıştırdığımızda bazen users önce gelecektir veya posts önce gelecektir.

/*
Buradaki amacımız işlemleri sıraya koymak. O yüzdende callback fonksiyonlar içerisinde yeni tanımlar yaparak ilerleye biliyoruz.
Yada şöyle bir durumda mümkün fetch işleminde karmaşıklık görüyorsanız daha da karmaşıklaştıralım
Örnek: 
*/
fetch("https://jsonplaceholder.typicode.com/users")
    .then((data) => data.json())
    .then((users) => {
        console.log("Users Yüklendi!", users)
        fetch("https://jsonplaceholder.typicode.com/posts/1")
            .then((data) => data.json())
            .then((posts) => {
                console.log("Post 1 Yüklendi!", posts)

                fetch("https://jsonplaceholder.typicode.com/posts/2")
                    .then((data) => data.json())
                    .then((data) => console.log("Post 2 Yüklendi!", data))
            });
    });
//Çalıştırdığımızda hepsi sırayla gelir çünki bu işlemleri sıraya koyduk.
//Az önce yukarıda yaptığımız gibi yaparsak. Sıraya koymazsak.
fetch("https://jsonplaceholder.typicode.com/users")
    .then((data) => data.json())
    .then((users) => {
        console.log("Users Yüklendi!", users)

    });

fetch("https://jsonplaceholder.typicode.com/posts/1")
    .then((data) => data.json())
    .then((posts) => {
        console.log("Post 1 Yüklendi!", posts)


    });

fetch("https://jsonplaceholder.typicode.com/posts/2")
    .then((data) => data.json())
    .then((data) => console.log("Post 2 Yüklendi!", data))

//Normalde users sonra post1 sonrada post 2 yüklenmesini bekleriz?
//İşte javascript öyle çalışmıyor. Ve test ettiğimizde karışık geliyor. Her seferinde daha farklı gelecektir.
//İşlemleri sıraya koymak için dikkat etmemiz gereken bir durum bu javascript için

//İşlemleri sıraya almak istiyorum ama bu kod oldukça karmaşık görünüyor diyenler için
//Buradada karşımıza yeni bir tanım çıkıyor. Bu tanımda async/await keywordleri
//Bu keywordleri kullanarak bu yazdığımız kodun çok daha temizini yazabiliyoruz.

//ÖRNEK: getData isminde asenkron bir fonksiyon yazalım.

async function getData() {
    const users = await (await fetch("https://jsonplaceholder.typicode.com/users")).json();
    const post1 = await (await fetch("https://jsonplaceholder.typicode.com/posts/1")).json();
    const post2 = await (await fetch("https://jsonplaceholder.typicode.com/posts/2")).json();

    console.log(users);
    console.log(post1);
    console.log(post2);
    //Burada kodu her çalıştırdığımızda bu sıralamaya bağlı olarak kodumuz düzenli bir şekilde çalışacaktır.
}
getData();
//Yukarıdaki yapıyla aşağıdaki yapıyı incelerseniz arada büyük farklar olduğunu görebilirsiniz. (Okuma anlamında) çalışma anlamında bir farklılık yok!

//Yukarıdaki gibi getData isminde fonksiyon kullanmak istemiyebilirsiniz. Yukarıda olduğu gibi doğrudan çalışsın diyebilirsiniz.
//Burada şöyle bir durum var async ifadesini kesinlikle yazmanız lazım. Bir fonksiyon mutlaka olmalı elinizde
//İllada bu isimde bir fonksiyonunuzun olmasını istiyorsanız anonim fonksiyon oluşturabilirsiniz.
//ÖRNEK:

(async () => {
    const users = await (await fetch("https://jsonplaceholder.typicode.com/users")).json();
    const post1 = await (await fetch("https://jsonplaceholder.typicode.com/posts/1")).json();
    const post2 = await (await fetch("https://jsonplaceholder.typicode.com/posts/2")).json();

    console.log(users);
    console.log(post1);
    console.log(post2);
})();

//Ve şimdi çalıştırdığımızdada yine aynı sonucu görüyoruz.

//Axios kullanımı
//Terminalimize: "npm i axios" yazıyoruz ve kütüphanemizi kuruyoruz. 
import axios from "axios";
// //Yukarıda yazdığımız kodu fetch'den axios'a devşiricez.
(async () => {
    const { data: users } = await axios("https://jsonplaceholder.typicode.com/users");
    const { data: post1 } = await axios("https://jsonplaceholder.typicode.com/posts/1");
    const { data: post2 } = await axios("https://jsonplaceholder.typicode.com/posts/2");
    //Axiosda bunların altında bire data geliyor. Yani data adında bir field(alan) getiriyor.
    console.log("users", users);
    console.log("post1", post1);
    console.log("post2", post2);
})();
  • Promises
Promises HK.
//BİR ÖNCEKİ DERSDEN ÖRNEK VERECEK OLURSAK:

import fetch from "node-fetch";

//Burada 
fetch("https://jsonplaceholder.typicode.com/users") //fetch diye bir kütüphane yazmışlar. Bir fonksiyonları var.
    .then((data) => data.json())//Sonra burada then ile devam ediyoruz. Bu then ne demek oluyor? Bu fetch aslında bir promise dönüyor demek oluyor.
    .then((users) => {
        console.log("Users Yüklendi!", users)
    });

//then ile devam eden fonksiyonlar nasıl yazabiliriz?
//ÖRNEK:

const getComments = () => {
    //Şimdi burada bir promise return etmemiz gerekiyor. Bu işlemi yapabilmemiz için. Nasıl return edebiliriz promise'ı?
    return new Promise(() => {
        //Burada işlemlerimizi artık yapabiliriz.
        console.log("comments");
    }) //Tanımını öncelikle koymamız lzm sonrasında parametresinde bir arrow fonksiyon oluşturuyoruz.
}

getComments().then(() => console.log("bitti"));
//Kodumuzu çalıştırdığımızda
//comments yazdı bitti logunu neden yazmadı sebebide şu bu promise'ın callback fonksiyonunda resolve ve reject adında iki tane parametre var
//Resolve demek:
//Bu işlem başarıyla gerçekleşmiş al sana data demek
//Reject ise:
//Bu kod çalışırken bir problem oluştu. Bunu reject(reddettim) demek oluyor.
//Şimdi bir promise resolve olduğunda .then içine düşer reject olduğunda catch içine düşer. Buradada hata yakalanır.
//ÖRNEK:

const getComments = () => {
    return new Promise((resolve, reject) => {
        console.log("comments");
        resolve();
    });
};
getComments()
.then(() => console.log("bitti"))
.catch((e) => console.log(e));

//Kodumuzu çalıştırdığımızda comments ve bitti dedi.

//Şimdi yukarıda biz datayı alıyorduk. fetch bize bir data sağlıyordu ve bunu biz kullanıyorduk biz nasıl yapıcaz?
//Promise'yi resolve ederken resolve()'nin içinde parametre geçebiliriz.
//ÖRNEK:

const getComments = () => {
    return new Promise((resolve, reject) => {
        //resolve("Comments"); //Burada sadece string dönmek zorunda değilsiniz numberda dönebilirsiniz. Objede dönebilirsiniz. ÖRNEK:
        resolve({ text: "Selam" });//Böyle çalıştırdığımız andada obje gelmiş oldu.
    });
};
getComments()
    .then((data) => console.log(data))
    .catch((e) => console.log(e));
//Çalıştırdığımız anda Comments yazdı!

//Şöyle bir şey yapalım. Comments(1) gönderildiğinde resolve olsun 2 gönderildiğinde reject olsun.
const getComments = (number) => {
    return new Promise((resolve, reject) => {
        if (number === 1){
        resolve({ text: "Selam" });
        }
        reject("Bir problem oluştu!");
    });
};
getComments(1)
    .then((data) => console.log(data))
    .catch((e) => console.log(e));

//Burada 1 gönderdiğimiz için program resolve olacak anlamına geliyor.
//Resolve oldu ve then içine düştü. 1 yerine 2 gönderirsek
getComments(2)
    .then((data) => console.log(data))
    .catch((e) => console.log(e));
//Bu seferde Bir problem oluştu! şeklinde logu görebiliyoruz.
//Bir promise'i bu şekilde oluşturabiliriz.

//Şimdi önceden axios ile yaptığımız işlemleri promise'mizde dönecek şekilde oluşturmaya çalışalım.
import axios from "axios";
const getUsers = () => {
    return new Promise(async (resolve, reject) => {
        const { data } = await axios("https://jsonplaceholder.typicode.com/users");
        resolve(data);
    });
};
// //Bu işlem gibi postları çeken bir tanım daha oluşturalım.
// //Burada ne yapıyoruz sürekli axios kullanmak yerine biraz daha böyle aksiyon arıyoruz ve kendi fonksiyonlarımız üzerinden datayı dönmeye çalışıyoruz. 
const getPost = (post_id) => {
    return new Promise(async (resolve, reject) => {
        const { data } = await axios("https://jsonplaceholder.typicode.com/posts/" + post_id);
        resolve(data);
    });
};
getUsers()
    .then((data) => console.log(data))
    .catch((e) => console.log(e));

getPost(1)
    .then((data) => console.log(data))
    .catch((e) => console.log(e));

//Şimdi böyle çalıştırdığımızda bizim bu işlemlerimiz sıralı gitmez çünki yine aynı şey söz konusu
//Burada bir promise var çalıştırıyoruz ve bunlar sıralı değil.
//Bunların ikiside ayrı asenkron fonksiyonlar kendi başlarına hayatlarına devam ediyorlar. Yani bir birlerine bağlı değiller.
//Sıraya koymak istersekde yine burada anonim fonksiyon yazabiliriz.
(async () => {
    await getUsers()
        .then((data) => console.log(data))
        .catch((e) => console.log(e));

    await getPost(1)
        .then((data) => console.log(data))
        .catch((e) => console.log(e));
})();
//Bunu böyle tekrar çalıştırdığımızda artık hep sıralı şekilde gelecektir.

//Şimdi biz bunların içindeki then'den ve catch'den kurtulmak istiyorsak şöyle yaparız.
//ÖRNEK:
(async () => {
    const users = await getUsers();
    const post = await getPost(1);

    console.log(users);
    console.log(post);
})();

//Önce userlar sonrada post gelmeli. Ve çalıştırdığımız zaman hep istediğimiz şekilde gelecektir.
//Peki burada bir hata olduğunda hatayı nasıl yakalıyacağız? Az önce catch ile bunu yapıyorduk ama burada nasıl yapacağız ?
//ÖRNEK:
(async () => {
    try {
        const users = await getUsers();
        const post = await getPost(551);

        console.log(users);
        console.log(post);
    } catch (e) {
        console.log(e);
    }

})();

//Kendimiz resolve yerine bir reject döndürelim ve bakalım.
const getUsers = () => {
    return new Promise(async (resolve, reject) => {
        const { data } = await axios("https://jsonplaceholder.typicode.com/users");
        resolve(data);
        //reject("Bir sorun oluştu!");
    });
};
const getPost = (post_id) => {
    return new Promise(async (resolve, reject) => {
        const { data } = await axios("https://jsonplaceholder.typicode.com/posts/" + post_id);
        //resolve(data);
        reject("Bir sorun daha oluştu!");
    });
};

//İlk sorun oluştuğu anda doğrudan catch bloguna düştü.
//Üstteki resolve olup alttaki reject olsaydı ne olurdu?
//Bu seferde yine bir sorun daha oluştu yazacaktır.
(async () => {
    try {
        const users = await getUsers();
        const post = await getPost(1);

        console.log(users);
        console.log(post);
    } catch (e) {
        console.log(e);
    }

})();

//Şimdi burada şöyle bir şey daha yapabiliriz.
//Bunların hepsini birdende çalıştırabiliriz. Nasıl?
//Promise.All diye bir ifade var. O ifade ile bütün promiseları çalıştırıp sonucu bekleyebiliriz.
//ÖRNEK:

//Burada bir array oluşturuyoruz ve buraya bütün promiselarımızı ekliyoruz.

const getUsers = () => {
    return new Promise(async (resolve, reject) => {
        const { data } = await axios("https://jsonplaceholder.typicode.com/users");
        resolve(data);
        //reject("Bir sorun oluştu!");
    });
};
const getPost = (post_id) => {
    return new Promise(async (resolve, reject) => {
        const { data } = await axios("https://jsonplaceholder.typicode.com/posts/" + post_id);
        resolve(data);
        //reject("Bir sorun daha oluştu!");
    });
};

Promise.all([getUsers(), getPost(1)])
    .then(console.log)
    .catch(console.log);
//Buda elinizde birden fazla sıralı çalıştırmak istediğiniz bir promise dizisi varsa kullanabileceğiniz yöntemlerden biri.
  • Array Functions
Array Functions HK.
/*
    push    = Array'in sonuna yeni bir eleman ekler.
    map     = Array içerisinde tek tek dönüyor.
    (Normalde array döndürmek for döngüsü kullanırdık.)
    (Map fonksiyonu diyorki lenght vermene ve for döngüsünü kullanmana gerek yok array'in bütün elemanlarını dönücem diyor.)
    find    = Array'in içerisinde verilen koşullarla arama yapar. (Bulduğu ilk kaydı getirir.)
    filter  = Filtreleme yapıyor. Örn: İsmi emirhan olanları getir gibi bütün kayıtları getirir.
    some    = Array'in içerisindeki elemanlardan biri verdiğimiz koşullara uyuyorsa "true" döner uymuyorsa "false" döner.
    every   = Some komutunun kardeşidir. (Array'in bütün elemanlarının şarta uymasını bekliyor.)
    include = Array'in içerisinde girilen ifade varmı yokmu kontrol etmemizi sağlayan ifadedir.
*/

const users = ["Mehmet", "Ahmet", "Murat"];

//Pust Kullanımı: Arrayin sonuna eleman ekliyor.
users.push("Ayşe");
users.push("Fatma");
console.log(users);

//Map: View compenentlerde en sık kullanılan fonksiyon bu
//Yaptığı işlem: Array içinde tek tek dönüyor.
//For döngüsünde başlangıç ve bitiş kullanırken map'de böyle bir şey kullanmaya gerek yok.
//Örnek array kullanımı:
for (let i = 0; i < users.length; i++) {
    console.log(users[i]);
}
//Map fonksiyonu diyorki length elle vermene gerek yok ben senin elemanlarının hepsini dönücem diyor.
users.map((item) => {
    console.log(item);
})

//Arrayin içerisinde objeler olsaydı
const users = [{
    name:"Emirhan",
    age: 10
},{
    name:"Emirhan",
    age: 29
},{
    name:"Deneme",
    age: 40
}];

users.map((item => {
    console.log(item);
}));

//item altındaki name'i yazdırmak içinse
users.map((item => {
    console.log(item.name);
}));

//Find:
//Arrayin içerisinde verilen koşullarla arama işlem yapar.
//İlk elemanı bulduğunda response'yi döner. Alttaki komut ilk bulduğu kaydı yazar.
const result = users.find((item) => item.name === "Emirhan" && item.age > 20);
console.log(result);

//Filter: Sık kullanılan method
//Filtreleme yapar. Çalışma şekli: İsmi emirhan olanları getir veya yaşı 20 den büyük olanları getir gibi vs vs.
//Find gibi tek kayıt getirmez hepsini getirir.
//Örnek kullanım 1:
const filtered = users.filter((item) => item.name === "Emirhan" && item.age < 20);

//console.log(filtered);
//Örnek kullanım 2:
const filtered = users.filter(
    ({name, age}) => name === "Emirhan" && age < 20);
console.log(filtered);

//Some: 
//Her hangi biri uyuyorsa yani: array'in içerisindeki elemanlardan biri koşula uyuyorsa true döner
//Uymuyorsa false döner.
const soming = users.some(
    ({age}) => age === 15);
console.log(soming);

//Every: Some'in kardeşi
//Array'in bütün elemanlarının şarta uymasını bekliyor.
const every = users.every(
    ({age}) => age > 15);
console.log(every);

//includes:
//Yaptığı işlem içinde geçiyormu? geçmiyormu? onu kontrol etmemizi sağlıyor.
//Buna göre true ve false yazıyor.
//Örnek:
const meyveler = ["elma", "armut", "muz"];
const isIncluded = meyveler.includes("muz");
console.log(isIncluded);

Bölüm2: Component'ler ile Çalışmak

  • Bir React Projesini Ayağa Kaldırmak(create-react-app)
Bir React Projesini Ayağa Kaldırmak(create-react-app) HK.
React projesini ayağa kaldırmak için facebook'un bize vermiş olduğu create-react-app repoyu kullanıcaz.
Repo Link: https://github.com/facebook/create-react-app

---TERMİNAL KOMUTLARI

-Yeni proje oluşturmak için
|npx create-react-app project name

-Projeyi çalıştırmak için
|npm start
  • Component Nedir?
Component Nedir? HK.
Compenent Nedir?:
Geliştirirken gerçekleştirilecek en küçük yapı ve birim için birer compenents geliştirip daha sonra onları tek bir
compenents altında birleştirerek görüntüleyeceğiz.
Yapıcağımız projelerde sürekli bir hareket olacak.
Sürekli bir şeyler güncellenecek, silenecek, eklenicek, güncellenicek bir sürü şey olacak.
Bu işlemleri en iyi şekilde en performanslı şekilde kullanıcılarımıza gösterebilmek için REACT gibi projelere ihtiyacımız var.
Büyükleri meydana getiren küçükler.
Büyük dediğimiz şey küçüklerin bir araya gelerek oluşturmuş olduğu yapılardır.
  • Component Oluşturmak/Kullanmak
Component Oluşturmak/Kullanmak HK.
/*
--- src/components/Header.js
Oluşturulan js dosyasının ismi küçük yazılabilir ama 
Fonksiyon tanımlarken baş harfinin büyük olduğuna dikkat edin!
Sebebi:
HTML etiketlerini render ediyoruz bazende kendi yazdığımız componentleri render ediyoruz.
Reactin bunu ayırt edebiliyor olması lzm baş harfi küçük olanlar aslında HTML ifadelerinin render edilmesi olarak
Baş harfi büyük olanlarda bizim yazdığımız custom componentlerin render edilmesi olarak algılanıyor.
*/

function Header() {
    return <div>Merhaba Ben Header Bileşeniyim</div>;
}
export default Header;

//src/App.js
import './App.css';
import React from 'react';
import Header from './components/Header';

/*
JSX'de dikkat etmemiz gereken kurallar.
Bir component'in içinde mutlaka kapsayıcı bir etiket olması gerekiyor.
Bazı Özel Tanımlı Keywordler Var JS İçin
İF,CLASS,FOR gibi özel tanımlı keywordlerimiz
Bunları JSX yazarken kullanmamamız önemli!
*/

function App() {
  return (
    <>
      <Header />
      <p className='xyz'>
        Lorem Ipsum is simply dummy text of the printing and typesetting industry.
        Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an
        unknown printer took a galley of type and scrambled it to make a type specimen book.
      </p>

      <label htmlFor='myinput'>
        Name
        <input id="myinput" />
      </label>
    </>
  );
}

export default App;
  • JSX ve Temel Kuralları
JSX ve Temel Kuralları HK.
-JSX NEDİR?
.js Uzantılı dosyamız var fakat içerisinde "HTML" ifadeler kullanılıyor.
Peki .js Uzantılı dosya bu "HTML" ifadeleri nasıl anlıyor(yorumluyor)?

"JSX"i kullanarak "HTML" yazar gibi "JS" yazabiliyoruz.

Örnek:
return (
  <div>
  </div>
); 
//Bu çalıştığında çalıştırılabilir bir js fonksiyonu arka planda getiriliyor.
Yukarıdaki kodu yazdığımızda aslında arka tarafta  şuna dönüştürülüyor.
return React.createElement("div", null, "Hello");

---FARK NEDİR?
Kodları yazarken bu "COMPONENT"leri oluştururken oldukça konforlu bir şekilde
yapma fırsatı yakalıyoruz.

Burada yazılanlar "HTML" değil | "HTML" görünümlü "JS"dir.
  • Componentlerde Değişken Render Etmek
Componentlerde Değişken Render Etmek HK.
//Componentlerde değişken render etmek
const name = "Emirhan";
const surname = "Pala";
function App() {
  return (
    <>
<h1>{name} {surname}</h1>
<h1>{`Benim adım ${name}, soyadım ${surname}`}</h1>
    </>
  );
}
  • Koşullu Render İşlemi
Koşullu Render İşlemi HK.
const name = "Emirhan";
const surname = "Pala";
//Koşullu render işlemi
const isLoggedIn = false;

function App() {
  return (
    <>
      <h1>
        {isLoggedIn && `Benim adım ${name}, soyadım ${surname}`}
        {!isLoggedIn && "Giriş Yapmadınız."}
        <br/>
        {isLoggedIn ? `Benim adım ${name}, soyadım ${surname}` : "Giriş Yapmadınız."}

      </h1>
    </>
  );
}

Bölüm3: Props ile Çalışmak

  • Props Nedir? Nasıl Kullanılır?
Props Nedir? Nasıl Kullanılır? HK.
Props dediğimiz şey oluşturacağımız componentlerde bir parametre geçmek istiyebiliriz. O parametrelerle o componentin initial görüntüsünü oluşturmak istiyebiliriz.
Bu durumlarda kullanabileceğimiz bir yapı.
Kısaca: Bir componentten başka bir componente veri aktarmak için kullanılan yapılar.

//src/App.js
import User from './components/User';

/*
Kendi yazdığımız componentlerde parametreler ve propertyler geçebiliriz.
Bool değer göndereceğimiz için bunu string olarak gönderemeyiz.
Bu yüzden {false} süslü parantezlerin içerisinde false veya true yazarak gönderebililiriz.
Aynı şekilde bir sayı göndereceğimiz zamandada süslü parantezler içerisinde gönderebiliriz.
String ifadelerde aynı şekilde gönderilebilir ama string gördediğimiz için çokta bir anlamı yok.
Propslar bu şekilde yazdığınız componentlere her hangi bir parametre geçip onu yazmış olduğunuz component'de karşılayıp
kullanabiliyorsunuz.
*/

function App() {
  return (
    <>
      <User name="Emirhan" surname="Pala" isLoggedIn={true} age={25} />
    </>
  );
}

//src/components/User.js
/*
Gönderdiğimiz bütün propertyler fonksiyonumuzda yazıcağımız props paremetresine düşüyor.
function User(props) kullanıp bütün değişkenlerin başına props yazmak yerine
props'un bir obje olduğunu biliyoruz o yüzden 
function User({name, surname, isLoggedIn}) şeklindede kullanabiliriz.
*/

//Örnek2:
//Burada gönderilen propertylerin sırasıyla karşıladığımız sıranın hiç bir anlamı(önemi) yok her hangi bir sırayla alıp kullanılabilir.
function User({name, surname, isLoggedIn, age}) {
    //console.log(props);
    return(
    <h1>
        {
            isLoggedIn ? `${name} ${surname} ${age}` : "Giriş yapmadınız."
        }
    </h1>
    );
}

/* Örnek1:
function User(props) {
    //console.log(props);
    return(
    <h1>
        {
            props.isLoggedIn ? `${props.name} ${props.surname}` : "Giriş yapmadınız."
        }
    </h1>
    );
}
*/

export default User;
  • Döngülerde "key" Prop'u
Döngülerde "key" Prop'u HK.
//src/App.js
import './App.css';
import User from './components/User';

/*
Şimdi elimizdeki bu componente bir array geçicez.
Yani prop olarak array vericez bu array'i componentin altında listelemeye çalışacağız.
*/
const friends = [
  {
    id:1,
    name:"Emirhan"
  },
  {
    id:2,
    name:"Sercan"
  },
  {
    id:3,
    name:"Deneme"
  },
  {
    id:4,
    name:"Test"
  }
];

//Örnek 2:
function App() {
  return (
    <>
      <User name="Emirhan" surname="Pala" isLoggedIn={true} age={25} friends={friends} />

    </>
  );
}

/*
Örnek 1:
function App() {
  return (
    <>
      <User name="Emirhan" surname="Pala" isLoggedIn={true} age={25} friends={["Sercan", "Deneme", "Test", "Test2", "Test3", "Test4"]} />
    </>
  );
}
*/

export default App;

//src/components/User.js
function User({ name, surname, isLoggedIn, age, friends }) {
    //console.log(props);
    return (
        <>
            <h1>
                {
                    isLoggedIn ? `${name} ${surname} ${age}` : "Giriş yapmadınız."
                }
            </h1>

            {
                //Örnek 2:
                //friends.map((friend) => <div key={friend.id}>{friend.id} - {friend.name}</div>)
                //Örnek 3: Böylede yazdırılabilir.
                friends.map((friend) => {
                return <div key={friend.id}>{friend.id} - {friend.name}</div>
                })

                //Örnek 1:
                //friends.map((friend, index) => <div key={index}>{index} - {friend}</div>)
            }
        </>
    );
}

export default User;
React Developer Tools HK.
React app içerisinde oluşturduğumuz componentleri ve bu componentler üzerine setlenen props ve state'leri görebildiğimiz debug yapabildiğimiz facebook tarafından geliştirilmiş google chrome dev tools üzerinde çalışan bir eklenti. Yukardaki mavi linke tıklayıp eklentiyi indirebilirsiniz.
  • Prop Types
Prop Types HK.
//src/components/User.js
/*
Prop Types:
Componentlere gönderdiğimiz propertylerin tiplerini belirleyebileceğimiz bir araç var.
Adı: Prop-Types 
Yaptığı İşlem:
App.JS'den gönderdiğimiz propertyleri örnek name string, surname string, isLoggedIn bool, age number ve friends array olarak gönderiliyor.
Bu yazdığımız componentleri sadece biz kullanmıyacağız bir takım arkadaşımız kullanabilir. Veya bu componenti bütün dünya ile paylaşabiliriz.
Bütün insanlık bunu kullanabilir. Dolayısıyla biz hangi property'de hangi veri tipini aldığımızı(kabul ettiğimizi) componentte belirtmemiz lazım.
Nasıl Kullanılır?
*/

import PropTypes from "prop-types";

function User({ name, surname, isLoggedIn, age, friends }) {
    //console.log(props);
    return (
        <>
            <h1>
                {
                    isLoggedIn ? `${name} ${surname} ${age}` : "Giriş yapmadınız."
                }
            </h1>

            {
                friends.map((friend) => {
                return <div key={friend.id}>{friend.id} - {friend.name}</div>
                })
            }
        </>
    );
}

User.propTypes = {
 name: PropTypes.string,
 surname: PropTypes.string,
 isLoggedIn: PropTypes.bool,
 age: PropTypes.number,
 friend: PropTypes.array,
}

export default User;

//src/App.js
import './App.css';
import User from './components/User';

const friends = [
  {
    id:1,
    name:"Emirhan"
  },
  {
    id:2,
    name:"Sercan"
  },
  {
    id:3,
    name:"Deneme"
  },
  {
    id:4,
    name:"Test"
  }
];

function App() {
  return (
    <>
      <User name="Emirhan" surname="Pala" isLoggedIn={true} age={25} friends={friends} />

    </>
  );
}

export default App;
  • Prop Types: isRequired
Prop Types: isRequired HK.
//src/components/User.js
/*
Prop Types: isRequired
Bu koşulu eklediğimizde değerlerin girileceği alanlar zorunlu hale geliyor.
*/

import PropTypes from "prop-types";

function User({ name, surname, isLoggedIn, age, friends }) {
    //console.log(props);
    return (
        <>
            <h1>
                {
                    isLoggedIn ? `${name} ${surname} ${age}` : "Giriş yapmadınız."
                }
            </h1>

            {
                friends.map((friend) => {
                return <div key={friend.id}>{friend.id} - {friend.name}</div>
                })
            }
        </>
    );
}

User.propTypes = {
 name: PropTypes.string.isRequired,
 surname: PropTypes.string.isRequired,
 isLoggedIn: PropTypes.bool.isRequired,
 age: PropTypes.number.isRequired,
 friend: PropTypes.array,
}

export default User;
  • Prop Types: oneOfType
Prop Types: oneOfType HK.
//src/components/User.js
import PropTypes from "prop-types";
/*
Prop Types: oneOfType
Bir property'de birden fazla veri tipinin gönderilmesine imkan tanımak için oneOfType adında bir tanımımız daha var.
Örnek: age ile matematiksel işlem yapmıyacaksak eğer hem string hemde number kabul edebiliriz.
oneOfType ile birden fazla veri tipi kabul edilebilir.
*/
function User({ name, surname, isLoggedIn, age, friends }) {
    //console.log(props);
    return (
        <>
            <h1>
                {
                    isLoggedIn ? `${name} ${surname} ${age}` : "Giriş yapmadınız."
                }
            </h1>

            {
                friends.map((friend) => {
                    return <div key={friend.id}>{friend.id} - {friend.name}</div>
                })
            }
        </>
    );
}

User.propTypes = {
    name: PropTypes.string.isRequired,
    surname: PropTypes.string.isRequired,
    isLoggedIn: PropTypes.bool.isRequired,
    age: PropTypes.oneOfType([
        PropTypes.number,
        propTypes.string
    ]).isRequired,
    friend: PropTypes.array,
}

export default User;
  • Prop Types: shape
Prop Types: shape HK.
//src/components/User.js
import PropTypes from "prop-types";
/*
shape
Obje olarak gönderdiğimiz propertylerde kullanabileceğimiz shape adında bir tanım daha var.
*/

function User({ name, surname, isLoggedIn, age, friends, adress }) {
    //console.log(props);
    return (
        <>
            <h1>
                {
                    isLoggedIn ? `${name} ${surname} ${age}` : "Giriş yapmadınız."
                }
            </h1>

            {adress.title} {adress.zip}
            <br/>
            <br/>
            {
                friends.map((friend) => {
                    return <div key={friend.id}>{friend.id} - {friend.name}</div>
                })
            }
        </>
    );
}

User.propTypes = {
    name: PropTypes.string.isRequired,
    surname: PropTypes.string.isRequired,
    isLoggedIn: PropTypes.bool.isRequired,
    age: PropTypes.oneOfType([
        PropTypes.number,
        PropTypes.string
    ]).isRequired,
    friend: PropTypes.array,
    adress: PropTypes.shape({
        title: PropTypes.string,
        zip: PropTypes.number
    })
}

export default User;

//src/App.js
import './App.css';
import User from './components/User';

const friends = [
  {
    id:1,
    name:"Emirhan"
  },
  {
    id:2,
    name:"Sercan"
  },
  {
    id:3,
    name:"Deneme"
  },
  {
    id:4,
    name:"Test"
  }
];

function App() {
  return (
    <>
      <User name="Emirhan" surname="Pala" isLoggedIn={true} age={25} friends={friends} adress={{
        title: "Etimesgut/Ankara",
        zip: "06600"
      }} />

    </>
  );
}

export default App;
  • Default Props
Default Props HK.
import PropTypes from "prop-types";
/*
Default Props
Her hangi bir tanım yapılmamış. Bir prop'a varsayılan bir değerde verebiliyoruz.
Örnek:
Değer yazılmamış prop'a veya prop gönderilmemiş ise otomatik olarak varsayılan atadığımız değeri veriyor.
*/

function User({ name, surname, isLoggedIn, age, friends, adress }) {
    //console.log(props);
    if (!isLoggedIn){
        return <div>Giriş yapmadınız.</div>
    }
    return (
        <>
            <h1>
                {
                    `${name} ${surname} ${age}`
                }
            </h1>

            
            <br/>
            <br/>
            {
                friends.map((friend) => {
                    return <div key={friend.id}>{friend.id} - {friend.name}</div>
                })
            }
        </>
    );
}

User.propTypes = {
    name: PropTypes.string.isRequired,
    surname: PropTypes.string.isRequired,
    isLoggedIn: PropTypes.bool.isRequired,
    age: PropTypes.oneOfType([
        PropTypes.number,
        PropTypes.string
    ]).isRequired,
    friend: PropTypes.array,
    adress: PropTypes.shape({
        title: PropTypes.string,
        zip: PropTypes.number,
    }),
};

User.defaultProps = {
    isLoggedIn: false
}

export default User;

Bölüm4: State Yönetimi

  • State Nedir? Nasıl Oluşturulur?
State Nedir? Nasıl Oluşturulur? HK.
Componentlerimiz üzerinde değerinin değişme potansiyeli olan bütün verileri tutan javascript objesi olarak nitelendirilebilir. Componentin her hangi bir anında değeri değişme potansiyeli olan bir veri state olarak tanımlanır
ve bu state değiştiği andada ilgili component render edilerek değişim ekrana yansıtılmış olur.

/*
State tanımlarken yapmamız gereken şey nedir?
React'ın altında useState adında bir hook var.
Bunu import ettikten sonra componentimizin içinde fonksiyonun içinde return'ün dışında tanım yapalım.
*/

import { useState } from "react";

function App() {
  //useState("")'e parametre verebiliyoruz.
  //Boş state'ye varsayılan ilk oluşturulurken bir değer ataması yapılabilir.
  const [name, setName] = useState("Emirhan");
  const [age, setAge] = useState(25);
  console.log(name, age)
  //İlk ekrana geldiğinde ifade ettiği değer Emirhan iken Alttaki butona tıklandıktan sonra Deneme olarak onun değişmesini istiyorum.
  return (
    <div className="App">
      <h1>Merhaba {name}</h1>
      <h2>{age}</h2>
      <button onClick={() => setName("Deneme")}>Change Name</button>
      <button onClick={() => setAge("55")}>Change Age</button>
      <button onClick={() => setAge("55") | setName("Deneme")}>Change All</button>
    </div>
  );

  /*
    NOT:
    Her hangi bir state güncellendiği anda return içerisindeki render işlemi baştan yapılır.
    Yani o görüntü yeniden oluşturulur. Çünki state değişti. State değiştiği içinde arayüzde görünmesi gereken ifade değişti.
    Dolayısıyla component render ediliyor. Bu componentler render edilirkende  dikkat etmemiz gereken durumlar var.
    Mesela gereksiz renderleri önlememiz gerekir?
  */
}

export default App;
  • Array States
Array States HK.
import { useState } from "react";
/*
Array States:
State'imizi array olarak tanımlayıp bu state'imizi nasıl güncelliyeceğimizi öğrenmeye çalışalım.
*/

function App() {
  const [name, setName] = useState("Emirhan");
  const [age, setAge] = useState(25);
  const [friends, setFriends] = useState(["Deneme", "Test"]);

  return (
    <div className="App">
      <h1>Merhaba {name}</h1>
      <h2>{age}</h2>
      <button onClick={() => setName("Deneme")}>Change Name</button>
      <button onClick={() => setAge("55")}>Change Age</button>
      <button onClick={() => setAge("55") | setName("Deneme")}>Change All</button>

      <hr />
      <br/><br/>

      <h2>Friends</h2>
      {
        friends.map((friend, index) => (
        <div key={index}>{friend}</div>
        ))
      }
      <button onClick={() => setFriends([...friends, "Yeni"]).push()}>Add new friend</button>

    </div>
  );
}
export default App;
  • Object States
Object States HK.
import { useState } from "react";

/* 
  Object States:
  State'imizi array olarak tanımlayıp bu state'imizi nasıl güncelliyeceğimizi öğrenmeye çalışalım.
*/

function App() {
  const [name, setName] = useState("Emirhan");
  const [age, setAge] = useState(25);
  const [friends, setFriends] = useState(["Deneme", "Test"]);
  const [address, setAddress] = useState({ title: "Ankara", zip: 16066 });


  return (
    <div className="App">
      <h1>Merhaba {name}</h1>
      <h2>{age}</h2>

      <button onClick={() => setName("Deneme")}>Change Name</button>
      <button onClick={() => setAge("55")}>Change Age</button>
      <button onClick={() => setAge("55") | setName("Deneme")}>Change All</button>

      <hr />
      <br /><br />
      <h2>Friends</h2>
      {friends.map((friend, index) => (
          <div key={index}>{friend}</div>
        ))}

      <br />
      <button onClick={() => setFriends([...friends, "Yeni"])}>Add new friend</button>

      <hr />
      <br /><br />

      <h2>Adress</h2>
      <div>{address.title} {address.zip}</div>

      <br />
      <button onClick={() => setAddress({...address, title: "Bursa", zip: 16600})}>Change adress</button>

    </div>
  );
}
  • Sayaç Uygulaması
Sayaç Uygulaması HK.
//src/components/Counter.js
import { useState } from 'react'

function Counter() {

  const [count, setCount] = useState(0);

  /*
        <button onClick={() => setCount(count-1)}>Decrease</button>
        <button onClick={() => setCount(count+1)}>Increase</button>
    Aşağıdaki gibi onclick işlemlerini bu probun içinde yapmak zorunda değiliz. Bunu dışarıda fonksiyon olarakta tanımlayıp kullanabiliriz.
    Her zaman bu methodun içerisindeki işlemler bu kadar kısa olmuyor. Dolayısıyla bunu dışarda bir fonksiyon olarakta tanımlamamız gerekebiliyor.
    Örnek:
  */

    const increase = () => {
        setCount(count+1)
      }
      const decrease = () => {
        setCount(count-1)
      }
      
  return (
    <div>
        <h1>{count}</h1>
        
        <button onClick={decrease}>Decrease</button>
        <button onClick={increase}>Increase</button>
    </div>
  )
}

export default Counter

//src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import Counter from './components/Counter';
import reportWebVitals from './reportWebVitals';

//Counter için indexde app'i göstermek yerine counteri çekiyorum.
//<App />

ReactDOM.render(
  <React.StrictMode>
    <Counter />
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
  • Re-Render Mantığını Anlamak (React vs JQuery)
Re-Render Mantığını Anlamak (React vs JQuery) Hk.
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>jQuery Example</title>
</head>

<body>
    <!--
        React componentlerimiz üzerindeki Re-Render mantığını anlayabilmek için yani yeniden render etme mantığını biraz daha
        iyi anlıyabilmek için şimdi aynı örneği hem jquery ile hemde react ile yapmaya çalışıcaz.
        Sonrasında bu örneklerin ilgili web sayfasını nasıl render ettiklerini görmeye ve anlamaya çalışıcaz.
        Aralarındaki farkları anlayamaya çalışıcaz.
        
        React ile yaptığımız sayaç uygulaması var. Bunun benzerinide jquery ile yapmaya çalışalım ve
        bunlar render edilirken yani bir butona basıldıktan sonra ekrandaki bir veri render edilirken ne gibi bir
        farklılıklar oluyor görelim.
        
        cdnjs.com
    -->

    <h1>0</h1>

    <button>Increase</button>

</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"
    integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ=="
    crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
    $(() => {
        $('button').on('click', () => {
            $('h1').html(1)
        })
    })
</script>

<!--
    Render işlemini görebilmek için
    Tarayıcımızdan Developer Tools'u açıyoruz. (F12 - Öğeyi Denetle)
    Sağ taraftan 3 noktalı olan yere tıklıyoruz.
    More Tools sekmesi altında Rendering butonuna tıklayıp açıyoruz.
    Ve alt bölümden Paint Flashing'i açıyoruz.
    Anlamı:
    Ekranda render edilen alanları bize ışık yakarak gösteriyor.
    
    jQuery ile yaptığımız olayda butona tıkladığımızda sürekli sayıyı değiştirdiğimiz alanı render ettiğini görüyoruz.
    Buda gereksiz bir render edilme işlemi oluyor.
    React dünyasında ise Increase butonunu jquery gibi sabit 1 yaptırıp denediğimizde
    Butona bir kere bastığımızda render işlemini yapıyor.
    İlk seferde normal çünki değeri 0'dı 1 oldu.
    Dolayısıyla render edilmesi lazımki değişiklikleri görebilelim.
    Asıl önemli olan şey zaten 1 olduğu halde yeniden o butona bastığımızda oranın render edilmiyor olması.
    1 Olduktan sonra tekrar butona bastığımızda render edilmiyor. Çünki 1 olduğu halde yine 1 set etmeye çalışıyoruz.
    Dolayısıyla sanal dom'da o zaten 1 olarak durduğu için gidip onu real dom'a yazmaya(değiştirmeye) çalışmıyor.
    jQuery örneğine tekrar dönüp baktığımızda orada her bastığımızda değiştirme işlemi yapılıyor.
    jQuery ve React arasında bir veriyi güncellerken ekranımızın her hangi bir alanınındaki bir state'i güncellerken
    ortaya çıkan rendering farkları bu şekilde diyebiliriz. En temel anlamda.
    Bundan sonraki React geliştirme kariyerinizde oldukça önemli.
    Bir React uygulaması geliştirirken dikkat etmeniz gereken en önemli durumlardan biri gereksiz renderlerin önüne geçmek.
    Burada React direkt olarak bunun önüne geçebiliyor burda ama önüne geçemediği ve dikkat etmeniz gereken belli başlı noktalar var.
    Onlarıda memories konularında değinmeye çalışacağız.
-->

</html>
  • Input için State Tanımı Yapmak
Input için State Tanımı Yapmak HK.
/*
Input için State Tanımı Yapmak:
Burada bir tane inputumuz olacak. Bu inputun içerisine bir veri girilmeye başlandığı anda biz o ilgili veriyi
state'imizede yazmaya çalışacağız.
Input'a bir veri girildiğinde onChange olduğunda Input gidip. O Inputun içindeki data'yı state'imizede yazmamız gerekiyor.
onChange olayıyla alakalı detayları bize veren bir event var. onChange'den bu dönüyor.
Sonra o Inputun içerisindeki ifade ettiği değeri state'imize yazmak istiyorsakda event.target.value kullanmamız gerekiyor.
<input value={name} onChange={(event) => setName(event.target.value)} />
Böyle yazmak zorundada değiliz. Şöylede yazabiliriz.
const onChangeName = ((event) => setName(event.target.value));
Bir tane daha field'ımız olursa peki ne olacak?
const [name, setName] = useState("");
    const [surname, setSurname] = useState("");
    const onChangeName = ((event) => setName(event.target.value));
    const onChangeSurname = ((event) => setSurname(event.target.value));
    
    return (
        <div>
            Name <br />
            <input value={name} onChange={onChangeName} />
            <br />
            <br />
            Surname <br />
            <input value={surname} onChange={onChangeSurname} />
            <br />
            {name} {surname}
        </div>
    );
    
    Onlarca inputumuz olursa peki oldukça zahmetli olmazmı?
    Bu state'i birden fazla yazmak yerine tek bir state'e indirdik.
    Sonra buradaki fonksiyonu teke indirdik.
    Ayın şekilde aşağı tarafta kullanırkende onChangedede her defasında dolayısıyla aynı
    fonksiyonu vererek işi kurtarmış olduk.
*/


import { useState } from 'react';

function InputExample() {

    const [form, setForm] = useState({
        name:"",
        surname:""
    });

    const onChangeInput = (e) => {
        console.log(e.target.name);

        setForm({ ...form, [e.target.name]: e.target.value })
    };

    return (
        <div>
            Name <br />
            <input name="name" value={form.name} onChange={onChangeInput} />
            <br />
            <br />

            Surname <br />
            <input name="surname" value={form.surname} onChange={onChangeInput} />
            <br />

            {form.name} {form.surname}
        </div>
    );
}

export default InputExample

Bölüm5: Component Lifecycle

  • useEffect
useEffect HK.
React componentleri üzerindeki yaşam döngüleri
Componentler DOM'a mount olduğu anda componentin üzerindenki bir state değiştiği anda aldığı bir prop değiştiği anda veya
unmount olduğu anda(DOM)'dan kaldırıldığı anda biz bu durumları yakalayıp o durumlara göre bir takım işlemler yaptırabiliyoruz.

import { useState, useEffect } from "react";

/*
useEffect:
Bir butona bastığımız anda bu name'i değiştirebiliriz ve bu state güncellenir dolayısıyla bu component render edilir.
Peki bu componentin render edilme durumunu veya her hangi bir statenin güncellenmesi eventinin halini nasıl yakalayabiliriz?
useState gibi useEffect adında bir hookumuz daha var.
Bu hooku kullanarak yaşam döngümüzdeki o eventleri yakalayabiliriz.
useState ve useEffect gibi hookları kullanırken bunlar hiç bir şekilde bir if yapısının içinde olmamalı
Componentin tepesinde bulunmalı ve her hangi bir kontrole tabi olmamalı.
*/

/*
  İlk etapda çalıştırıp console'ye baktığımızda state güncellendi diyor. Bunun gelmesinin sebebi ne?
  Başta bir state oluşturduk ve ona varsayılan değer ataması yapıyoruz. Dolayısıyla o state güncellendi diye logu
  görüntülemiş oluyor.
  Butona her bastığımızda yeni bir log üretiyor. Bu ne demek oluyor?
  State component üzerindeki her hangi bir state güncellendiği anda biz yukarda kullandığımız useEffect ifadesi ile o durumu
  yakalayabiliyoruz demek oluyor.
  Component didMount 
  Reactin daha önceki versiyonunda class componentler kullanıyorduk. Orada özel tanımlı bir fonksiyon vardı component didMount adında.
  Onu kullanmak için Peki o ne işe yarıyor?
  Component dom'a mount olduğu anda o anı yakalayabilmemizi sağlayan bir fonksiyon.
  */

function App() {

  const [number, setNumber] = useState(0);
  const [name, setName] = useState("Emirhan");

  /*
    Arrow fuctionu yazdıktan sonra bir virgül atıp ikinci parametrede array açıp kapatma yapmamız gerekiyor.
    Bunun adı Teknik Termanilojide dependency array olarak geçiyor.(Bağımlılık array'i) olarak geçiyor.
    Eğer [] bunu boş bırakırsak içine bir şey yazmaksak anlamı nedir?
    Component mount edildiği anı yakalarsın demek oluyor.
  */

  useEffect(() => {
    console.log("Component mount edildi!");
  }, []);

  //Bu ifade sadece state'nin güncellendiği anda yazacağı anlamına geliyor.
  useEffect(() => {
     console.log("State güncellendi!");
  })
  //Number güncellendiğinde bundan haberdar olmak istiyorsak ne yapabiliriz?
  //Hangi state'nin değişimini yakalamak istiyorsak bunun içine [] onun değerini vermemiz gerekiyor.
  useEffect(() => {
     console.log("Number state güncellendi!");
  }, [number]);
  //Sadece Number ve Name statesinin güncellendiğini görmek için
  useEffect(() => {
     console.log("Number veya Name state güncellendi!");
  }, [number, name]);
  //[] Array'in içerisine istediğimiz kadar state elemanını ekliyebiliriz.

  //Ayrı görüntülemek içinde
  useEffect(() => {
      console.log("Number state güncellendi!");
    }, [number]);

    useEffect(() => {
      console.log("Name state güncellendi!");
    }, [name]);

  return (
    <div className="App">
      <h1>{number}</h1>
      <button onClick={() => setNumber(number + 1)}>Click</button>
      <hr />
      <h1>{name}</h1>
      <button onClick={() => setName("Deneme")}>Click</button>
    </div>
  );
}

export default App;
  • Component Unmount
Component Unmount
//App.js
import Counter from "./components/Counter";
import { useState } from "react";
/*
useEffect:
Bir butona bastığımız anda bu name'i değiştirebiliriz ve bu state güncellenir dolayısıyla bu component render edilir.
Peki bu componentin render edilme durumunu veya her hangi bir statenin güncellenmesi eventinin halini nasıl yakalayabiliriz?
useState gibi useEffect adında bir hookumuz daha var.
Bu hooku kullanarak yaşam döngümüzdeki o eventleri yakalayabiliriz.
useState ve useEffect gibi hookları kullanırken bunlar hiç bir şekilde bir if yapısının içinde olmamalı
Componentin tepesinde bulunmalı ve her hangi bir kontrole tabi olmamalı.
*/

/*
  İlk etapda çalıştırıp console'ye baktığımızda state güncellendi diyor. Bunun gelmesinin sebebi ne?
  Başta bir state oluşturduk ve ona varsayılan değer ataması yapıyoruz. Dolayısıyla o state güncellendi diye logu
  görüntülemiş oluyor.
  Butona her bastığımızda yeni bir log üretiyor. Bu ne demek oluyor?
  State component üzerindeki her hangi bir state güncellendiği anda biz yukarda kullandığımız useEffect ifadesi ile o durumu
  yakalayabiliyoruz demek oluyor.
  Component didMount 
  Reactin daha önceki versiyonunda class componentler kullanıyorduk. Orada özel tanımlı bir fonksiyon vardı component didMount adında.
  Onu kullanmak için Peki o ne işe yarıyor?
  Component dom'a mount olduğu anda o anı yakalayabilmemizi sağlayan bir fonksiyon.
  */

function App() {
  const [isVisible, setIsVisible] = useState(true)
  return (
    <div className="App">
      {isVisible && <Counter />}
      <br />
      <button onClick={() => setIsVisible(!isVisible)}>Toggle Counter</button>
    </div>
  );
}

export default App;

//Counter.js
import { useState, useEffect } from "react";

function Counter() {

    const [number, setNumber] = useState(0);
    const [name, setName] = useState("Emirhan");

    /*
      Arrow fuctionu yazdıktan sonra bir virgül atıp ikinci parametrede array açıp kapatma yapmamız gerekiyor.
      Bunun adı Teknik Termanilojide dependency array olarak geçiyor.(Bağımlılık array'i) olarak geçiyor.
      Eğer [] bunu boş bırakırsak içine bir şey yazmaksak anlamı nedir?
      Component mount edildiği anı yakalarsın demek oluyor.
    */

    useEffect(() => {
        console.log("Component mount edildi!");
        //number'in değerini her saniye 1 er 1 er arttıralım.

        const interval = setInterval(() => {
            //Trick(Hile,Kandırmak vs.) öğrenelim setNumber içerisinde arrow function oluşturduğumuzda
            //() parantez içine yazdığımız n aslında numberin o anda ifade etmiş olduğu değer oluyor.
            setNumber((n) => n + 1);
        }, 1000);
        /*
        Toggle Countere bastığımızda component kayboluyor ama çalışmaya devam ettiği için hata veriyor.
        Nedeni: Bizim burada bir asenkron bir işlemimiz var her saniyede bu güncelleme işlemi yapılıyor.
        O zaman mantık şu olmalı.
        Bu component unMount edildiği anda bu setInterval'i bizim durdurmamız gerekiyor.
        En aşağıda return işlemi yaptığımızda componentin unmount edildiğini anlayabiliyoruz.
        Bu yine class componentlerde ayrı bir fonksiyon olarak ayrı özel tanımlı fonksiyon olarak kullanılıyordu.
        Artık öyle bir yapıya gitmektense daha temiz bir şekilde didmount'un içinde bunu bize vermişler.
        */

        /*
        Oluşturulan atanan intervali durdurmamız lazım
        durdurmak içinde javascript bize clearInterval adında bir fonksiyon daha veriyor.
        Buna parametre olarak intervali vermemiz yeterli olacaktır.
        */
        return () => clearInterval(interval);//console.log("Component unmount edildi!");

        /*
        Bunu nerelerde kullanabiliriz?:
        Bir componentiniz var o component mount edildiği anda bir web socket bağlantısı başlatıyor.
        Fakat o componenti kapattığınız andada web socket bağlantısını eğer kapatmazsanız 
        Sürekli olarak napar?
        Yani ilgili o web socketten gelen datayı componentin içerisinde bir yerde yazıyorsunuz gösteriyorsunuz diyelim.
        Eğer o web socket bağlantısını kapatmazsanız. Sürekli arka planda aslında yine o dom'a yazmaya çalışacaktır ve yine
        console'da hataları alacaksınız.
        Veya bu tip interval işlerinde kullanabilirsiniz.
        Componenti unmount ettikten sonra o componenti tekrardan güncellemeye çalışabilecek ne varsa aslında onları o işlemleri
        durdurmanız özellikle gerekiyor.
        */
    }, []);

    //Bu ifade sadece state'nin güncellendiği anda yazacağı anlamına geliyor.
    // useEffect(() => {
    //   console.log("State güncellendi!");
    // })
    //Number güncellendiğinde bundan haberdar olmak istiyorsak ne yapabiliriz?
    //Hangi state'nin değişimini yakalamak istiyorsak bunun içine [] onun değerini vermemiz gerekiyor.
    // useEffect(() => {
    //   console.log("Number state güncellendi!");
    // }, [number]);
    //Sadece Number ve Name statesinin güncellendiğini görmek için
    // useEffect(() => {
    //   console.log("Number veya Name state güncellendi!");
    // }, [number, name]);
    //[] Array'in içerisine istediğimiz kadar state elemanını ekliyebiliriz.

    //Ayrı görüntülemek içinde
    useEffect(() => {
        console.log("Number state güncellendi!");
    }, [number]);

    return (
        <div>
            <h1>{number}</h1>
            <button onClick={() => setNumber(number + 1)}>Click</button>
        </div>
    )
}

export default Counter

Bölüm6: Telefon Rehberi Uygulaması

  • Ne geliştireceğiz
Ne geliştireceğiz Hk.
/*
   Bu bölüme kadar öğrendiklerimiz ile bir örnek uygulama geliştirmeye çalışarak öğrendiklerimizi 
   pekiştirmeye çalışacağız.
   Bunu react uygulaması olarak oluşturucaz.
   Nedir bu uygulama?
   Telefon rehberi uygulaması olarak düşünebilirsiniz.
*/

//src/App.js
import './App.css';

import Contacts from "./components/Contacts";

function App() {
  return (
    <div className="App">
      <Contacts />
    </div>
  );
}

export default App;

//src/components/Contacts/Form/index.js
import React from 'react';

function Form() {
  return (
    <div>Form</div>
  )
}

export default Form

//src/components/Contacts/List/index.js
import React from 'react';

function List() {
  return (
    <div>Contact List</div>
  )
}

export default List

//src/components/Contacts/index.js
import React from 'react';

import List from './List';
import Form from './Form';

function Contacts() {
    return (
        <div>
            <List />
            <Form />
        </div>
    )
}

export default Contacts
  • Form Component'inin Geliştirilmesi
Form Component'inin Geliştirilmesi HK.
//index.js
import { useState, useEffect } from 'react';
import Contacts from '..';

/* 2: 
Buradaki kayıtları bir state'e eklemek gerekiyor.
List componentinde onları listeleyebilelim. 
Eğer kullanıcı kayıtlarını form componentleri içerisindeki bir statede tutarsak
Bu state'yi List componentine nasıl taşıyabiliriz? Böyle bir problemimiz var.
O yüzden biz o state'yi yani kullanıcıların ekleneceği state'yi eğer bu contacts componentinde tutarsak ve
Bu state'ye ekleme(set) işlemi yapılacak olan fonksiyonu eğer form componentine geçersem problem kalmayacak.
*/
const initialFormValues = { fullname: "", phone_number: "" }
function Form({ addContact, contacts }) {
//console.log(addContact);
    const [form, setForm] = useState(initialFormValues);

    /*
     contacts değişmiş ise eğer inputun içini boşalt diyebiliriz.
     Bu değiştiğinde ne demektir.
     Bi kayıt eklendiyse eğer o kayıttan sonra ekleme işleminden sonra temizleme yapabilirim demek.
     setForm işlemini onSubmit içinden alıp useEffect içine ekleyebiliriz.
    */
    useEffect(() => {
        setForm(initialFormValues)
    }, [contacts])

    const onChangeInput = (e) => {
        setForm({...form, [e.target.name]: e.target.value})
    }

    //SetForm işlemini onSubmit'de yapmak istemiyorsak bunu yan etkileri kullanarak yapmak istiyorsak. useEffecti dahil ettikten sonra
    const onSubmit = (e) => {
        e.preventDefault();

        if (form.fullname === "" || form.phone_number === ""){
            return false;
        }
        addContact([...contacts, form]);
    }

    return (
        /* 1:
        form elementinin(etiketinin) varsayılan bir davranışı var. Bu davranış nedir?
        Bu formun gideceği bir endpoint olur o endpointi gider veriyi oraya gönderir veya çeker.
        */
        <form onSubmit={onSubmit}>
            <div>
                <input name="fullname" placeholder='Full Name' value={form.fullname} onChange={onChangeInput}></input>
            </div>
            <div>
                <input name="phone_number" placeholder='Phone Number' value={form.phone_number} onChange={onChangeInput}></input>
            </div>
            <div>
                <button onClick={onSubmit}>Add</button>
            </div>
        </form>
    )
}

export default Form

//Contact/index.js
import { useEffect, useState } from 'react';

import List from './List';
import Form from './Form';

function Contacts() {
    const [contacts, setContacts] = useState([]);

    /*
    Contacts'e bir atama yapıldığında o son güncel halini görmeye çalışalım.
    useEffect:
    Form componentinde form submit edildiğinde ekleme işlemi yapıyoruz ya
    Bu ekleme işlemi yapıldıktan sonra bu elimizdeki array'in son halini görmek için yazıyoruz.
    Test sonucu kayıt eklerken birin üstünde kayıt eklediğimizde bir kayıt gösteriyor.
    
    Bunun için formumuza contacts={contacts} ekliyoruz ve son olarakta submit içerisindeki
    arrayimizede ...contacts, form ifadesini yazdığımızda sorun çözülmüş oluyor.
    */
    useEffect(() => {
        console.log(contacts);
    }, [contacts])

    return (
        <div>
            <List />
            <Form addContact={setContacts} contacts={contacts} />
        </div>
    )
}
  • Kayıtların Listelenmesi
Kayıtların Listelenmesi HK.
//src/components/Contacts/List/index.js
import React from 'react';

function List({contacts}) {
  return (
    <div>
        <ul>
            {
                contacts.map((contact, i) => <li key={i}>{contact.fullname}</li>)
            }
        </ul>
    </div>
  )
}

//src/components/Contacts/index.js

<List />//'i kaldırıyoruz.
<List contacts={contacts} /> //Ekliyoruz.
  • Filtreleme İşlemi
Filtreleme İşlemi
//src/components/Contacts/index.js
import { useEffect, useState } from 'react';

import List from './List';
import Form from './Form';

function Contacts() {
    const [contacts, setContacts] = useState([{
        fullname: "Emirhan",
        phone_number: 1234421
    },{
        fullname: "Deneme",
        phone_number: 456457
    },{
        fullname: "Test",
        phone_number: 987659
    }]);

    /*
    Contacts'e bir atama yapıldığında o son güncel halini görmeye çalışalım.
    useEffect:
    Form componentinde form submit edildiğinde ekleme işlemi yapıyoruz ya
    Bu ekleme işlemi yapıldıktan sonra bu elimizdeki array'in son halini görmek için yazıyoruz.
    Test sonucu kayıt eklerken birin üstünde kayıt eklediğimizde bir kayıt gösteriyor.
    
    Bunun için formumuza contacts={contacts} ekliyoruz ve son olarakta submit içerisindeki
    arrayimizede ...contacts, form ifadesini yazdığımızda sorun çözülmüş oluyor.
    */
    useEffect(() => {
        console.log(contacts);
    }, [contacts])

    return (
        <div>
            <List contacts={contacts} />
            <Form addContact={setContacts} contacts={contacts} />
        </div>
    )
}

export default Contacts

//src/components/Contacts/Form/index.js
import { useState, useEffect } from 'react';
import Contacts from '..';

/* 2: 
Buradaki kayıtları bir state'e eklemek gerekiyor.
List componentinde onları listeleyebilelim. 
Eğer kullanıcı kayıtlarını form componentleri içerisindeki bir statede tutarsak
Bu state'yi List componentine nasıl taşıyabiliriz? Böyle bir problemimiz var.
O yüzden biz o state'yi yani kullanıcıların ekleneceği state'yi eğer bu contacts componentinde tutarsak ve
Bu state'ye ekleme(set) işlemi yapılacak olan fonksiyonu eğer form componentine geçersem problem kalmayacak.
*/
const initialFormValues = { fullname: "", phone_number: "" }
function Form({ addContact, contacts }) {
//console.log(addContact);
    const [form, setForm] = useState(initialFormValues);
    
    /*
     contacts değişmiş ise eğer inputun içini boşalt diyebiliriz.
     Bu değiştiğinde ne demektir.
     Bi kayıt eklendiyse eğer o kayıttan sonra ekleme işleminden sonra temizleme yapabilirim demek.
     setForm işlemini onSubmit içinden alıp useEffect içine ekleyebiliriz.
    */
    useEffect(() => {
        setForm(initialFormValues)
    }, [contacts])

    const onChangeInput = (e) => {
        setForm({...form, [e.target.name]: e.target.value})
    }

    //SetForm işlemini onSubmit'de yapmak istemiyorsak bunu yan etkileri kullanarak yapmak istiyorsak. useEffecti dahil ettikten sonra
    const onSubmit = (e) => {
        e.preventDefault();

        if (form.fullname === "" || form.phone_number === ""){
            return false;
        }
        addContact([...contacts, form]);
    }

    return (
        /* 1:
        form elementinin(etiketinin) varsayılan bir davranışı var. Bu davranış nedir?
        Bu formun gideceği bir endpoint olur o endpointi gider veriyi oraya gönderir veya çeker.
        */
        <form onSubmit={onSubmit}>
            <div>
                <input name="fullname" placeholder='Full Name' value={form.fullname} onChange={onChangeInput}></input>
            </div>
            <div>
                <input name="phone_number" placeholder='Phone Number' value={form.phone_number} onChange={onChangeInput}></input>
            </div>
            <div>
                <button onClick={onSubmit}>Add</button>
            </div>
        </form>
    )
}

export default Form

//src/components/Contacts/List/index.js
import React, { useState } from 'react';

function List({ contacts }) {
    const [filterText, setFilterText] = useState("");

    const filtered = contacts.filter((item) => {
        return Object.keys(item).some((key) => 
            item[key]
                .toString()
                .toLowerCase()
                .includes(filterText.toLocaleLowerCase())
        );
    });

    console.log("filtered", filtered);

    return (
        <div>

            <input placeholder='Filter Contact' value={filterText} onChange={(e) => setFilterText(e.target.value)}></input>
            <ul>
                {
                    filtered.map((contact, i) => <li key={i}>{contact.fullname}</li>)
                }
            </ul>
        </div>
    )
}

export default List
  • Stil Tanımlarının Yapılması
Stil Tanımlarının Yapılması HK.
//Önceki dersde yaptığımız contacts-app'in üzerinde uygulayacağız. className geçicez.

//src/App.css
.App {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

//src/components/Contacts/Form/index.js
import { useState, useEffect } from 'react';
import Contacts from '..';

/* 2: 
Buradaki kayıtları bir state'e eklemek gerekiyor.
List componentinde onları listeleyebilelim. 
Eğer kullanıcı kayıtlarını form componentleri içerisindeki bir statede tutarsak
Bu state'yi List componentine nasıl taşıyabiliriz? Böyle bir problemimiz var.
O yüzden biz o state'yi yani kullanıcıların ekleneceği state'yi eğer bu contacts componentinde tutarsak ve
Bu state'ye ekleme(set) işlemi yapılacak olan fonksiyonu eğer form componentine geçersem problem kalmayacak.
*/
const initialFormValues = { fullname: "", phone_number: "" }
function Form({ addContact, contacts }) {
//console.log(addContact);
    const [form, setForm] = useState(initialFormValues);
    
    /*
     contacts değişmiş ise eğer inputun içini boşalt diyebiliriz.
     Bu değiştiğinde ne demektir.
     Bi kayıt eklendiyse eğer o kayıttan sonra ekleme işleminden sonra temizleme yapabilirim demek.
     setForm işlemini onSubmit içinden alıp useEffect içine ekleyebiliriz.
    */
    useEffect(() => {
        setForm(initialFormValues)
    }, [contacts])

    const onChangeInput = (e) => {
        setForm({...form, [e.target.name]: e.target.value})
    }

    //SetForm işlemini onSubmit'de yapmak istemiyorsak bunu yan etkileri kullanarak yapmak istiyorsak. useEffecti dahil ettikten sonra
    const onSubmit = (e) => {
        e.preventDefault();

        if (form.fullname === "" || form.phone_number === ""){
            return false;
        }
        addContact([...contacts, form]);
    }

    return (
        /* 1:
        form elementinin(etiketinin) varsayılan bir davranışı var. Bu davranış nedir?
        Bu formun gideceği bir endpoint olur o endpointi gider veriyi oraya gönderir veya çeker.
        */
        <form onSubmit={onSubmit}>
            <div>
                <input name="fullname" placeholder='Full Name' value={form.fullname} onChange={onChangeInput}></input>
            </div>
            <div>
                <input name="phone_number" placeholder='Phone Number' value={form.phone_number} onChange={onChangeInput}></input>
            </div>
            <div className='btn'>
                <button onClick={onSubmit}>Add</button>
            </div>
        </form>
    )
}

export default Form

//src/components/Contacts/List/index.js
import React, { useState } from 'react';
import Form from '../Form';

function List({ contacts }) {
    const [filterText, setFilterText] = useState("");

    const filtered = contacts.filter((item) => {
        return Object.keys(item).some((key) => 
            item[key]
                .toString()
                .toLowerCase()
                .includes(filterText.toLocaleLowerCase())
        );
    });

    console.log("filtered", filtered);

    return (
        <div>

            <input placeholder='Filter Contact' value={filterText} onChange={(e) => setFilterText(e.target.value)}></input>
            <ul className='list'>
                {
                    filtered.map((contact, i) => 
                    <li key={i}>
                    <span>{contact.fullname}</span>
                    <span>{contact.phone_number}</span>
                    </li>)
                }
            </ul>

            <p>
                Total Contacts ({filtered.length})
            </p>
        </div>
    )
}

export default List

//src/components/Contacts/index.js
import { useEffect, useState } from 'react';

import "./styles.css"

import List from './List';
import Form from './Form';

function Contacts() {
    const [contacts, setContacts] = useState([{
        fullname: "Emirhan",
        phone_number: 1234421
    },{
        fullname: "Deneme",
        phone_number: 456457
    },{
        fullname: "Test",
        phone_number: 987659
    }]);

    /*
    Contacts'e bir atama yapıldığında o son güncel halini görmeye çalışalım.
    useEffect:
    Form componentinde form submit edildiğinde ekleme işlemi yapıyoruz ya
    Bu ekleme işlemi yapıldıktan sonra bu elimizdeki array'in son halini görmek için yazıyoruz.
    Test sonucu kayıt eklerken birin üstünde kayıt eklediğimizde bir kayıt gösteriyor.
    
    Bunun için formumuza contacts={contacts} ekliyoruz ve son olarakta submit içerisindeki
    arrayimizede ...contacts, form ifadesini yazdığımızda sorun çözülmüş oluyor.
    */
    useEffect(() => {
        console.log(contacts);
    }, [contacts])

    return (
        <div id='container'>
            <h1>Contacts</h1>
            <List contacts={contacts} />
            <Form addContact={setContacts} contacts={contacts} />
        </div>
    )
}

export default Contacts

//src/components/Contacts/styles.css
#container {
    width: 400px;
    background-color: aliceblue;
    padding: 20px;
}

input {
    width: 100%;
    padding: 5px;
    box-sizing: border-box;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
}

ul,
li {
    margin: 0;
    padding: 0;
    list-style-type: none;
}

.list {
    margin: 15px 0;
}

.list>li {
    background-color: antiquewhite;
    padding: 5px;
    margin-bottom: 2px;
    display: flex;
    justify-content: space-between;
}

.btn {
    display: flex;
    justify-content: flex-end;
    padding: 5px 0;
}

.btn>button {
    padding: 5px;
    width: 60px;
}

Bölüm7: Stillendirme

  • Stil Tanımı Yapmak
Stil Tanımı Yapmak HK.
React componentlerini stillendirirken bilmemiz gereken temel konular.
create-react-app ile projemizi oluşturup içerisinde App.css dosyasında csslerimizi görüyoruz.
App.js dosyamızı açtığımızdada hazırlanan css dosyası doğrudan import edilmiş ve component içerisinde kullanılabilmiş.
Normal html yazarken react ile uygulama yapmazken etiketlerde style diye bir property var.
Buraya biz inline olarak bi still tanımı girerek kullanabiliyoruz.

//src/App.js
import logo from './logo.svg';
import './App.css';

function App() {
    /*
    style kullanırken süslü parantezlerimizi açıyoruz.
    ÖNEMLİ: Nasıl kullanıcaz? Obje olarak tanım vererek.
    Obje tanımlarken ne kullanıyorduk yine süslü parantez.
    
    CSS içinde tanımladıklarımızı burada öyle kullanamıyoruz.
    Örnek:
    Javascriptte bir değişken oluştururken veya bir objenin içinde key tanımı yaparken tire ifadesi kullanılamaz.
    background-color vericeksek bunu backgroundColor şeklinde yazıp devam etmemiz gerekiyor.
    Burada dikkat edilmesi gereken tek şey 
    1.Obje verdiğinize emin olmanız lazım.
    2.CSS Tanımının içinde - vs tanımlar varsa bunları bunları camel case olarak yazmanız gerekecek.
    Dikkat edilmesi gereken şeyler böyle.
    Çok sıklıkla inline tanımları verilmiyor ama verilmesi gereken durumlarda olabiliyor. O zamanda bunlara dikkat etmeniz gerekecek.
    Bir başka konu:
    Bootstrap kullanıcaksınız dimi?
    Bunu kullanırken ne yapıyorsunuz? Bootstrap size bir js ve css dosyası veriyor.
    Bunu html dosyanıza import edip kullanmaya başlayabiliyorsunuz.
    Bu şekilde dışardan endpointteki css dosyasını alıp. İmport edebilirmiyim diye sorabilirsiniz?
    cdnjs.com girelim
    bootstrap yazalım.
    gerekli dosyaları bulup yazalım.
    pek fazla tercih edilmiyor ama index.html içine bulduğumuz link tagini gömelim.
    getbootstrap.com girelim
    docs açalım
    aşağıdan components sekmesine tıklayıp bişiyler ekliyelim.
    ve sonuç olarak dışardanda bir css dosyasını alıp buraya yerleştirebiliyoruz.
    */
    return (
        <div className="App" >
            <header className="App-header" >
                <p>Edit <code> src / App.js </code> and save to reload. </p>

                <div style={{ color: "red", backgroundColor: "white", paddingTop: 50 }}>
                    Lorem Ipsum, dizgi ve baskı endüstrisinde kullanılan mıgır metinlerdir. Lorem Ipsum,
                    adı bilinmeyen bir matbaacının bir hurufat numune kitabı oluşturmak üzere bir yazı
                    galerisini alarak karıştırdığı 1500'lerden beri endüstri standardı sahte metinler
                    olarak kullanılmıştır. Beşyüz yıl boyunca varlığını sürdürmekle kalmamış, aynı
                    zamanda pek değişmeden elektronik dizgiye de sıçramıştır. 1960'larda Lorem Ipsum
                    pasajları da içeren Letraset yapraklarının yayınlanması ile ve yakın zamanda Aldus
                    PageMaker gibi Lorem Ipsum sürümleri içeren masaüstü yayıncılık yazılımları ile popüler olmuştur.
                </div>

                <div class="alert alert-primary" role="alert">
                    A simple primary alert—check it out!
                </div>
            </header>
        </div>
    );
}

export default App;
  • Module CSS
Module CSS
//src/components/B/styles.module.css
.title{
    color: green;
}

//src/components/B/index.js
import styles from "./styles.module.css";

console.log("B", styles);

function B() {
  return (
    <div className={styles.title}>B</div>
  )
}

export default B

//src/components/A/styles.module.css
.title{
    color: red;
}

//src/components/A/index.js
import styles from "./styles.module.css";

/*
styles.css leri module olarak kullandığımızda classNamelerimiz çakışmadan hayatına devam edebiliyor.
css dosyalarımızın adını ilk başta styles.module.css olarak değiştirip sonrada yukarda kullanılan import gibi projemize dahil ediyoruz.
*/

console.log("A", styles);

function A() {
  return (
    <div className={styles.title}>A</div>
  )
}

export default A

//src/App.js
import './App.css';

import A from './components/A';
import B from './components/B';

/*
    Module CSS Kavramı ve neden ihtiyacımız olduğunu bilmek için önce problemin ne olduğunu anlamamız lazım:
    Onun için 2 tane component oluşturuyoruz.
    Componentlerde 2 tane ayrı ayrı css tanımı import edicez.
    Bu css tanımlarının içindede aynı className'lere sahip birer eleman olacak.
    Sonrasında sonucun ne olacağını görecez.
*/

function App() {
    return (
        <div className="App" >
            <header className="App-header" >
                <A />
                <B />
            </header>
        </div>
    );
}

export default App;

Bölüm8: Data Fetching

  • Native Fetch
Native Fetch HK.
//src/App.js
import './App.css';
import Users from './components/Users';

/*
Her hangi bir veri kaynağına gidip. O veri kaynağındaki ilgili veriyi aldıktan sonra ekranımızda nasıl gösterebiliriz? Bu işlemlere bakıcaz.
Fake Api: jsonplaceholder.typicode.com
*/

function App() {
  return (
    <div className="App">
      <Users />
    </div>
  );
}

export default App;

//src/components/Users.js
import { useEffect, useState } from 'react'

/*
    Link: https://jsonplaceholder.typicode.com/users
    Şimdi bu veriye ne zaman erişmek istiyoruz?
    Users componentimiz mount edildiği anda o veriye erişmek için gerekli olan isteği başlatmak istiyorum.
    Artık o istek ne zaman sonuçlanırsada ekranımda göstermiş olucam.
*/

function Users() {

    const [users, setUsers] = useState([]);
    const [isLoading, setIsLoading] = useState(true);


    useEffect(() => {
        /*
        Bize veri kaynağına erişebilmek için native(yerli) bir tanım veriliyor.
        fetch adında bir tanım var. Biz bu fetchi kullanarak ek her hangi bir kütüphane kullanmadan gerekli veri kaynağına erişe biliyoruz.
        */
        fetch("https://jsonplaceholder.typicode.com/users")
            .then((res) => res.json())
            /* Örnek 1 Loading:
            .then((data) => {
                setUsers(data);
                setIsLoading(false);
            });
            */
           .then((data) => setUsers(data))
           .catch((e) => console.log(e))
           /*
           Finally kısmında yani eğer .then((data) => setUsers(data)) then'e düşmezsek doğrudan catch kısmına düşersek isLoading sürekli 
           true olarak kalacak. Bunu istemeyiz. Bunun önüne geçmek için hem then içine hemde catch içine belki setIsLoading(false) diye
           konulabilir ama onu yapmaktansa tek bir yerde bu işlemi yapmak daha mantıklı.
           Aşağıdaki gibi setIsLoading'i false'ye çekersek aynı işlemi yapmış olucaz.
           */
          .finally(() => setIsLoading(false));
    }, [])
    return (
        <div>
            <h1>Users</h1>
            {isLoading && <div>Loading...</div>}
            {users.map((user, i) => (
                <div key={i}>{user.name}</div>
            ))}
        </div>
    )
}

export default Users
  • Axios
Axios HK.
//App.js
import Users from './components/Users';

/*
Her hangi bir veri kaynağına gidip. O veri kaynağındaki ilgili veriyi aldıktan sonra ekranımızda nasıl gösterebiliriz? Bu işlemlere bakıcaz.
Fake Api: jsonplaceholder.typicode.com
*/

function App() {
  return (
    <div className="App">
      <Users />
    </div>
  );
}

export default App;

//Users.js
/*
Native fetch ile yapabildiğimiz bütün işlemleri aslında farklı kütüphaneler kurarakda yapabiliyoruz.
En çok bilineni: axios
Axios'u kullanarak yine fetch ile yaptığımız ne varsa her birini yapabiliyoruz.
Aralarında çok büyük bir farklar yok.
Ne fark var? Neden fetch i yada axios'ı tercih etmeliyim gibi. 
fetch kullandığımız zaman bize body'i json olarak vermiyor. stringify olarak veriyor.
dolayısıyla bizim bunu elle json'a çevirmemiz gerekiyordu.
Axios'da öyle bir durum yok buradan body'i bize obje olarak dönüyor.
Axios'u kullandığımızda her hangi bir siteyi iptal edebiliriz veya timeout belirleyebiliriz. Fetch'de bu durum söz konusu değil
Birde axios'un daha geniş bir browser desteği var. Fetch'de ise açıklamalarında gördüğünüz sınırlamalarla karşınıza çıkıyor.
Axios'u kullanabilmemiz için modül olarak kurmamız gerekiyor.
npm i axios
Yüklendikten sonra...
Fetch ile yaptıklarımızı axios'a çevirelim.
*/
import { useEffect, useState } from 'react'
import axios from "axios"
function Users() {

    const [users, setUsers] = useState([]);
    const [isLoading, setIsLoading] = useState(true);

    useEffect(() => {
        axios("https://jsonplaceholder.typicode.com/users")
            .then((res) => setUsers(res.data))
            .catch((e) => console.log(e))
            .finally(() => setIsLoading(false));
    }, [])
    return (
        <div>
            <h1>Users</h1>
            {isLoading && <div>Loading...</div>}
            {users.map((user, i) => (
                <div key={i}>{user.name}</div>
            ))}
        </div>
    )
}

export default Users

Bölüm9: React Router

  • Kurulum
React Router Kurulum HK.
//Önceki derslerde öğrendiğimiz gibi önce componentslerimizi oluşturalım.
//src/components/About.js
import React from 'react'

function About() {
  return (
    <div>About</div>
  )
}

export default About

//src/components/Home.js
import React from 'react'

function Home() {
  return (
    <div>Home</div>
  )
}

export default Home

//src/components/Users.js
import React from 'react'

function Users() {
  return (
    <div>Users</div>
  )
}

export default Users

//src/App.js
import './App.css';
import react from 'react';
import { BrowserRouter as Router, Switch, Route, Link, } from "react-router-dom";

import Home from "./components/Home";
import Users from "./components/Users";
import About from "./components/About"; 

/*
Kurulum için
reactrouter.com/web/
Reactteki routing yapısı:
Aşağıdaki gibi yüklemeleri yapıp kullandığımızda
Home ekranındayız. Örnek: About'a bastığımızda adres satırı ile content'in sayfa yenilenmeden değiştiğini görüyoruz.
Butona bastığımızda hiç bir şekilde sayfa yenilenmiyor.
Tarayıcıdaki adress yerine endpoint
Link içerisinde gelen sayfada content
Yeni versiyonda switch olmadığı için routes kullanılıyor.
Eski versiyonunu kullanmak için
---Önceki kurduğumuz react-router-dom'u kaldıralım.
-npm uninstall react-router-dom
---Şimdi ise eski versiyonu indirmek için alttaki kodu yazalım.
npm install [email protected]
*/

function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
            <li>
              <Link to="/users">Users</Link>
            </li>
          </ul>
        </nav>

        <Switch>
          <Route path="/about" component={About} />
          <Route path="/users" component={Users} />
          <Route path="/" component={Home} />
        </Switch>
      </div>
    </Router>
  );
}

export default App;
  • Exact Prop
Exact Prop HK.
//src/App.js
import './App.css';
import react from 'react';
import { BrowserRouter as Router, Switch, Route, Link, } from "react-router-dom";

import Home from "./components/Home";
import Users from "./components/Users";
import About from "./components/About"; 

function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
            <li>
              <Link to="/users">Users</Link>
            </li>
          </ul>
        </nav>
        {
          /*
          Switch çalışma mantığı: 
          Switch'e girdiğiniz zaman 1'incisine bakıyor.
          Başta home'nin olduğunu düşünürsek path ney? /
          Peki bu ifade diğer sayfalardada varmı? Var o yüzden eşleştiği için direk olarak bunu çalıştırıyor bizim için.
          Yani burada bir düzenli ifade var ve o düzenli ifade ile bizim endpointimiz bir yere kadar eşleştiği için
          Doğrudan onu kabul ediyor. Onu çalıştırıyor.
          Yani home en üstteyken diğer sayfalara girdiğimizde endpoint değişirken content değişmiyecektir.
          Bundan kurtulmak için Home'u en altta yazarız.
          İllede en üste yazıp kullanacaksakda şöyle yaparız.
          exact bunu yazarsak yine o sorundan kurtulmuş oluyoruz.
          exact propuda bu işe yarıyor.
          */
        }
        <Switch>
        <Route path="/" exact component={Home} />
          <Route path="/about" component={About} />
          <Route path="/users" component={Users} />
        </Switch>
      </div>
    </Router>
  );
}

export default App;
  • URL Parameters
URL Parameters HK.
//src/App.js
import './App.css';
import react from 'react';
import { BrowserRouter as Router, Switch, Route, Link, } from "react-router-dom";

import Home from "./components/Home";
import Users from "./components/Users";
import About from "./components/About"; 
import User from "./components/User"; 

function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
            <li>
              <Link to="/users">Users</Link>
            </li>
          </ul>
        </nav>
        {
          /*
          Bir route'ye parametre nasıl gönderebiliriz?
          Örnek site: https://v5.reactrouter.com/web/example/url-params
          Route'yi belirlerken path'ine /:id şöyle bir parametre alacağımız alanı belirlememiz gerekiyor.
          : iki nokta üst üste dedikten sonra artk parametre ismini ne olarak belirlemek istiyorsak.
          Onu yazmamız gerekiyor.
          Sonra o route'nin componentindede useParams() hook'unu kullanarak o id'yi veya gönderdiğimiz parametrenin
          İsmi neyse onu karşılayıp hemen altındada kullanabiliyormuşuz.
          */
        }
        <Switch>
        <Route path="/" exact component={Home} />
          <Route path="/about" component={About} />
          <Route path="/users" component={Users} />
          <Route path="/user/:id" component={User} />
        </Switch>
      </div>
    </Router>
  );
}

export default App;

//src/components/User.js
import { useParams, Link } from 'react-router-dom'
import { useEffect, useState } from 'react'
import axios from 'axios';

function User() {
    const [loading, setLoading] = useState(true);
    const [user, setUsers] = useState({});
    const { id } = useParams();

    useEffect(() => {
        axios(`https://jsonplaceholder.typicode.com/users/${id}`)
            .then((res) => setUsers(res.data))
            .finally(() => setLoading(false))
    }, [user])

    return (
        <div>
            {loading && <div>Loading...</div>}
            {!loading &&
                <>

                    <h1>User Detail</h1>
                    <code>{JSON.stringify(user)}</code>
                    <br />
                    <br />
                    <Link to={`/user/${parseInt(id) + 1}`}>Next User ({parseInt(id) + 1})</Link>
                </>
            }
        </div>
    )
}

export default User

//src/components/Users.js
import { Link } from 'react-router-dom'
import { useEffect, useState } from 'react'
import axios from 'axios'

function Users() {
  const [loading, setLoading] = useState(true);
  const [users, setUsers] = useState([]);

  useEffect(() => {
    axios("https://jsonplaceholder.typicode.com/users")
    .then((res) => setUsers(res.data))
    .finally(() => setLoading(false))
  }, [])
  
  return (
    <div>
      {loading && <div>Loading...</div>}
      <h1>Users</h1>
      <ul>
        {
          users.map((user) => 
            <li key={user.id}>
              <Link to={`/user/${user.id}`}>{user.name}</Link>
            </li>
          )
        }
      </ul>
    </div>
  )
}

export default Users
  • Nesting
Nesting HK.
//src/components/Users.js
import { Link, Switch, Route, useRouteMatch } from 'react-router-dom'
import { useEffect, useState } from 'react'
import axios from 'axios'
import User from "./User"; 

function Users() {
  const [loading, setLoading] = useState(true);
  const [users, setUsers] = useState([]);
  const { path, url } = useRouteMatch();

  console.log(path, url);

  useEffect(() => {
    axios("https://jsonplaceholder.typicode.com/users")
      .then((res) => setUsers(res.data))
      .finally(() => setLoading(false))
  }, [])

  return (
    <div>
      {loading && <div>Loading...</div>}
      <h1>Users</h1>
      <ul>
        {
          users.map((user) =>
            <li key={user.id}>
              <Link to={`${url}/${user.id}`}>{user.name}</Link>
            </li>
          )
        }
      </ul>

      {
        /*
        Nesting(İç içe routing) İşlemlerini Nasıl Yapabiliriz?
        Örnek Link: https://v5.reactrouter.com/web/example/nesting
        Burdaki yapılan örnekte liste kaybedilmeden direkt olarak alt tarafta görüntüleme işlemini yapmışlar.
        Bizde bunun aynısı user üzerinde yapmaya çalışıcaz.
        Burada önemli olan şeyler baktığımız sitedeki 
        Topics'in orada içeriğine baktığımızda
        useRouteMatch hook'unu kullanmış.
        Yine bu componentin içinde bir switch daha var.
        Bu switch'in içindede yine linkler var.
        O zaman bizimde yapmamız gereken şey Users componentimizde yeni bir switch yapısı
        kurmamız gerekiyor.
        Switch içerisinde path tanımları var bunlar nereden geliyor?
        useRouteMatch()'den geliyor.
        */
      }

      <Switch>
        <Route exact path={path}>
          <h3>Please select a user.</h3>
        </Route>
        <Route path={`${path}/:id`} component={User} />
      </Switch>

    </div>
  )
}

export default Users

//src/App.js
import './App.css';
import react from 'react';
import { BrowserRouter as Router, Switch, Route, Link, } from "react-router-dom";

import Home from "./components/Home";
import Users from "./components/Users";
import About from "./components/About"; 

function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
            <li>
              <Link to="/users">Users</Link>
            </li>
          </ul>
        </nav>
        {

        }
        <Switch>
        <Route path="/" exact component={Home} />
          <Route path="/about" component={About} />
          <Route path="/users" component={Users} />
        </Switch>
      </div>
    </Router>
  );
}

export default App;

//src/components/User.js
import { useParams, Link } from 'react-router-dom'
import { useEffect, useState } from 'react'
import axios from 'axios';

function User() {
    const [loading, setLoading] = useState(true);
    const [user, setUsers] = useState({});
    const { id } = useParams();

    useEffect(() => {
        axios(`https://jsonplaceholder.typicode.com/users/${id}`)
            .then((res) => setUsers(res.data))
            .finally(() => setLoading(false))
    }, [user])

    return (
        <div>
            {loading && <div>Loading...</div>}
            {!loading &&
                <>

                    <h1>User Detail</h1>
                    <code>{JSON.stringify(user)}</code>
                    <br />
                    <br />
                    <Link to={`/users/${parseInt(id) + 1}`}>Next User ({parseInt(id) + 1})</Link>
                </>
            }
        </div>
    )
}

export default User
  • NavLink
NavLink HK.
//src/App.js
import './App.css';
import react from 'react';
import { BrowserRouter as Router, Switch, Route, NavLink, } from "react-router-dom";

import Home from "./components/Home";
import Users from "./components/Users";
import About from "./components/About";
/*
NavLink:
Aslında bunun link'in aynısı gibi düşünebilirsiniz.
Tek farkı şu aktif olan linki biraz daha still olarak özelleştirmek isterseniz
Kullanabileceğiniz kullanışlı bir component.
Örnek:
Home butonuna bastığınızda home ekranında olduğunuz için bu home butonunu biraz daha farklı
aktif olarak göstermek isterseniz. Kullanabileceğiniz bir component.
*/
function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <NavLink exact activeClassName="active" to="/">Home</NavLink>
            </li>
            <li>
              <NavLink activeClassName="active" to="/about">About</NavLink>
            </li>
            <li>
              <NavLink activeClassName="active" to="/users">Users</NavLink>
            </li>

            {/*
            Kullanım-1:
            <li>
              <NavLink exact activeStyle={{ backgroundColor: "black", color: "#fff"}} to="/">Home</NavLink>
            </li>
            <li>
              <NavLink activeStyle={{ backgroundColor: "black", color: "#fff"}} to="/about">About</NavLink>
            </li>
            <li>
              <NavLink activeStyle={{ backgroundColor: "black", color: "#fff"}} to="/users">Users</NavLink>
            </li>*/
            }
          </ul>
        </nav>
        {

        }
        <Switch>
          <Route path="/" exact component={Home} />
          <Route path="/about" component={About} />
          <Route path="/users" component={Users} />
        </Switch>
      </div>
    </Router>
  );
}

export default App;

//src/App.css
.App {
  text-align: center;
}
.active{
  background-color: black;
  color: white;
  padding: 1px;
}
a{
  text-decoration: none;
}

//src/components/Users.js
import { NavLink, Switch, Route, useRouteMatch } from 'react-router-dom'
import { useEffect, useState } from 'react'
import axios from 'axios'
import User from "./User"; 

function Users() {
  const [loading, setLoading] = useState(true);
  const [users, setUsers] = useState([]);
  const { path, url } = useRouteMatch();

  console.log(path, url);

  useEffect(() => {
    axios("https://jsonplaceholder.typicode.com/users")
      .then((res) => setUsers(res.data))
      .finally(() => setLoading(false))
  }, [])

  return (
    <div>
      {loading && <div>Loading...</div>}
      <h1>Users</h1>
      <ul>
        {
          users.map((user) =>
            <li key={user.id}>
              <NavLink activeClassName="active" to={`${url}/${user.id}`}>{user.name}</NavLink>
            </li>
          )
        }
      </ul>

      <Switch>
        <Route exact path={path}>
          <h3>Please select a user.</h3>
        </Route>
        <Route path={`${path}/:id`} component={User} />
      </Switch>

    </div>
  )
}

export default Users
  • No Match (404)
No Match (404) HK.
//src/components/Error404.js
import React from 'react'

function Error404() {
  return (
    <div>
        <h2>This page was not found!</h2>
    </div>
  )
}

export default Error404

//src/App.js
import './App.css';
import react from 'react';
import { BrowserRouter as Router, Switch, Route, NavLink, } from "react-router-dom";

import Home from "./components/Home";
import Users from "./components/Users";
import About from "./components/About";
import Error404 from "./components/Error404";
function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <NavLink exact activeClassName="active" to="/">Home</NavLink>
            </li>
            <li>
              <NavLink activeClassName="active" to="/about">About</NavLink>
            </li>
            <li>
              <NavLink activeClassName="active" to="/users">Users</NavLink>
            </li>
          </ul>
        </nav>
        {
          /*
          No Match (404):
          Hata ekranlarını nasıl karşılayabiliriz?
          Kullanıcı gelip bizim var olmayan bir endpointimiz var diyelim.
          Örnek: localhost:3000/asdfasf
          Buraya girmeye çalıştığı anda normal görüntüyü almak yerine
          hata ekranı gösterimi yapabiliriz.
          Bunu yapmak içinde linklerimizde yine Route kullanıyoruz.
          Path olarak * vericez. Hata sayfamız için componentimizi oluşturuyoruz.
          Burada yıldız koymamızın sebebi her türlü eşleş diyoruz.
          Yani yukardaki Routelerin hiç biriyle eşleşmediyse her türlü bununla eşleş
          Çünki hiç biriyle eşleşmediyse öyle bir ekran yoktur. Dolayısıyla bununla eşleşmesi yeterli diyoruz.
          */
        }
        <Switch>
          <Route path="/" exact component={Home} />
          <Route path="/about" component={About} />
          <Route path="/users" component={Users} />
          <Route path="*" component={Error404} />
        </Switch>
      </div>
    </Router>
  );
}

export default App;

Bölüm10: Form Yönetimi

  • Kurulum
useFormik HK.
Biz reactte form yönetimlerimizi yaparken formik adındaki aracı kullanarak form yönetimimizi çok daha basit bir şekilde yapabiliyoruz.
Şuan react dünyasında karşımıza çıkan form kontrolü, yönetimi anlamında en basit en kullanılabilir durumda olanı formik.
Çok basitçe form işlemlerimizi bununla çok az eforla yapabiliyoruz.

Site: formik.org

import './App.css';

import { Formik, Field, Form } from 'formik'

function App() {
  return (
    <div className="App">
      <h1>Sign Up</h1>
      <Formik
        initialValues={{
          firstName: '',
          lastName: '',
          email: '',
        }}
        onSubmit={(values) => {
          console.log(values);
        }}
      >
        <Form>
          <label htmlFor="firstName">First Name</label>
          <Field id="firstName" name="firstName" placeholder="Jane" />

          <br />
          <br />

          <label htmlFor="lastName">Last Name</label>
          <Field id="lastName" name="lastName" placeholder="Doe" />

          <br />
          <br />

          <label htmlFor="email">Email</label>
          <Field
            id="email"
            name="email"
            placeholder="[email protected]"
            type="email"
          />

          <br />
          <br />

          <button type="submit">Submit</button>
        </Form>
      </Formik>
    </div>
  );
}

export default App;
  • handleSubmit & handleChange
handleSubmit & handleChange
import './App.css';

import { Formik } from 'formik'
/*
Şimdi biz istiyoruzki formik'in bize vermiş olduğu bu form ve field componentlerini kullanmayalım.
Doğrudan HTML'deki formu ve input nesnelerini, etiketlerini kullanalım.
Bunun için bir kaç değişime ihtiyacımız var.
İmporttan  Field, Form siliyoruz.
*/
function App() {
  return (
    <div className="App">
      <h1>Sign Up</h1>
      <Formik
        initialValues={{
          firstName: '',
          lastName: '',
          email: '',
        }}
        onSubmit={(values) => {
          console.log(values);
        }}
      >
        {
          /*
          Eğer kendi inputlarımızı kullanmak istersek yani html etiketlerini kullanarak ilerlemek istersek
          Alttaki gibi bir yapıya bürünmemiz gerekiyor.
          Burda form ve field componentlerini kullandığımız zaman iş biraz daha kolay oluyor aslında ama çoğu zaman
          Onları kullanamayabiliyoruz. Bir takım özelleştirmeler vs gerekiyor. İşte o gibi durumlardada bu yöntemi uygulayabiliriz.
          */
          ({handleSubmit, handleChange}) => (
            <form onSubmit={handleSubmit}>
          <label htmlFor="firstName">First Name</label>
          <input name='firstName' onChange={handleChange} />

          <br />
          <br />

          <label htmlFor="lastName">Last Name</label>
          <input name='lastName' onChange={handleChange} />

          <br />
          <br />

          <label htmlFor="email">Email</label>
          <input name='email' onChange={handleChange} />

          <br />
          <br />

          <button type="submit">Submit</button>
        </form>
          )
        }
      </Formik>
    </div>
  );
}

export default App;
  • Radio / Checkbox / Dropdown
Radio / Checkbox / Dropdown HK.
import './App.css';

import { Formik } from 'formik'
/*
Radio / Checkbox / Dropdown
*/
function App() {
  return (
    <div className="App">
      <h1>Sign Up</h1>
      <Formik
        initialValues={{
          firstName: 'Emirhan',
          lastName: 'Pala',
          email: '[email protected]',
          gender: 'male',
          hobies: [],
          country: "turkey",
        }}
        onSubmit={(values) => {
          console.log(values);
        }}
      >
        {
          ({ handleSubmit, handleChange, values }) => (
            <form onSubmit={handleSubmit}>
              <label htmlFor="firstName">First Name</label>
              <input name='firstName' value={values.firstName} onChange={handleChange} />

              <br />
              <br />

              <label htmlFor="lastName">Last Name</label>
              <input name='lastName' value={values.lastName} onChange={handleChange} />

              <br />
              <br />

              <label htmlFor="email">Email</label>
              <input name='email' value={values.email} onChange={handleChange} />

              <br />
              <br />

              <span>Male</span>
              <input type="radio" name='gender' value="male" onChange={handleChange} checked={values.gender === "male"} />
              <span>Female</span>
              <input type="radio" name='gender' value="female" onChange={handleChange} checked={values.gender === "female"} />

              <br />
              <br />

              <div>
                <input type="checkbox" name='hobies' value="Football" onChange={handleChange} />
                Football
              </div>

              <div>
                <input type="checkbox" name='hobies' value="Cinema" onChange={handleChange} />
                Cinema
              </div>

              <div>
                <input type="checkbox" name='hobies' value="Photography" onChange={handleChange} />
                Photography
              </div>

              <br />
              <br />

              <select name="country" value={values.country} onChange={handleChange}>
                <option value="turkey">Turkey</option>
                <option value="england">England</option>
                <option value="usa">USA</option>
              </select>

              <br />
              <br />
              <button type="submit">Submit</button>

              <br />
              <br />
              <code>{JSON.stringify(values)}</code>
            </form>
          )
        }
      </Formik>
    </div>
  );
}

export default App;
  • useFormik
useFormik HK.
import './App.css';

import { useFormik } from 'formik'
/*
useFormik:
Şimdi bu aşağıda yazdığımız kodumuzu daha temiz ve daha güzel hale getirmek için neler yapabiliriz? Onlara bakmaya çalışacağız.
Aşağıda düzelttiğimiz kodlarla ne yapmış olduk şimdi?
Render kısmını(return) biraz daha sadeleştirmiş olduk.
Artık bu componentimiz daha temiz bir görünüme kavuşmuş oldu.
*/
function App() {
  const {handleSubmit, handleChange, values} = useFormik({
    initialValues: {
      firstName: 'Emirhan',
      lastName: 'Pala',
      email: '[email protected]',
      gender: 'male',
      hobies: [],
      country: "turkey",
    },
    onSubmit: (values) => {
      console.log(values);
    },
  });
  return (
    <div className="App">
      <h1>Sign Up</h1>
      <form onSubmit={handleSubmit}>
        <label htmlFor="firstName">First Name</label>
        <input name='firstName' value={values.firstName} onChange={handleChange} />

        <br />
        <br />

        <label htmlFor="lastName">Last Name</label>
        <input name='lastName' value={values.lastName} onChange={handleChange} />

        <br />
        <br />

        <label htmlFor="email">Email</label>
        <input name='email' value={values.email} onChange={handleChange} />

        <br />
        <br />

        <span>Male</span>
        <input type="radio" name='gender' value="male" onChange={handleChange} checked={values.gender === "male"} />
        <span>Female</span>
        <input type="radio" name='gender' value="female" onChange={handleChange} checked={values.gender === "female"} />

        <br />
        <br />

        <div>
          <input type="checkbox" name='hobies' value="Football" onChange={handleChange} />
          Football
        </div>

        <div>
          <input type="checkbox" name='hobies' value="Cinema" onChange={handleChange} />
          Cinema
        </div>

        <div>
          <input type="checkbox" name='hobies' value="Photography" onChange={handleChange} />
          Photography
        </div>

        <br />
        <br />

        <select name="country" value={values.country} onChange={handleChange}>
          <option value="turkey">Turkey</option>
          <option value="england">England</option>
          <option value="usa">USA</option>
        </select>

        <br />
        <br />
        <button type="submit">Submit</button>

        <br />
        <br />
        <code>{JSON.stringify(values)}</code>
      </form>
    </div>
  );
}

export default App;
  • Form Validasyonları - 1
Form Validasyonları - 1 HK.
//src/App.css
.App {
  text-align: center;
}

label {
  display: block;
}

//src/App.js
import './App.css';
import Signup from './components/Signup'

/*
Form validasyonları 1
Validasyon işlemlerini yup ile yapıyoruz.
Link: https://github.com/jquense/yup
*/
function App() {

  return (
    <div className="App">
      <Signup />
    </div>
  );
}

export default App;

//src/components/validations.js
import * as yup from 'yup';

const validations = yup.object({
  email: yup.string().email().required(),
  password: yup.string().min(5).required(),
  passwordConfirm: yup.string().oneOf([yup.ref('password')]).required()
});
//oneOf Methodu: Bu method ile password onayının kontrolünü yapabiliyoruz.

export default validations;

//src/components/Signup.js
import React from 'react'
import { useFormik } from 'formik'
import validationSchema from './validations'

function Signup() {
    const { handleSubmit, handleChange, values } = useFormik({
        initialValues: {
            email: '',
            password: '',
            passwordConfirm: '',

        },
        onSubmit: (values) => {
            console.log(values);
        },
        validationSchema,
    });

    return (
        <div>
            <h1>Sign Up</h1>
            <form onSubmit={handleSubmit}>

                <label>Email</label>
                <input name='email' value={values.email} onChange={handleChange} />

                <br />
                <br />

                <label>Password</label>
                <input name='password' value={values.password} onChange={handleChange} />

                <br />
                <br />

                <label>Confirm Password</label>
                <input name='passwordConfirm' value={values.passwordConfirm} onChange={handleChange} />

                <br />
                <br />


                <br />
                <br />
                <button type="submit">Submit</button>

                <br />
                <br />
                <code>{JSON.stringify(values)}</code>
            </form>
        </div>
    )
}

export default Signup
  • Form Validasyonları - 2
Form Validasyonları - 2 HK.
//src/App.css
.App {
  text-align: center;
}

label {
  display: block;
}

.error{
  color: red;
}

//src/App.js
import './App.css';
import Signup from './components/Signup'

/*
Form validasyonları 2
Hata mesajlarının gösterimini yapıcaz.
*/
function App() {

  return (
    <div className="App">
      <Signup />
    </div>
  );
}

export default App;

//src/components/Signup.js
import React from 'react'
import { useFormik } from 'formik'
import validationSchema from './validations'

/*
ÖNEMLİ:
Kullanıcı deneyimini daha iyi bir hale getirmek için inputa bir veri girdiğimizde o inputun ve diğer inputların
O anki hata mesajlarını göstermemeli ne zaman ki o inputtan ayrılırsam ancak o zaman göstermeli.
Kullanıcı deneyimi için bu önemli bir durum.
Bunu yapmak içinde ilgili inputa daha önce focus olmuşmu yani touch olmuşmu oraya işte girmişmi bunu anlayıp
Ona göre oraya girmemiz lazım. Onuda şöyle yapıcaz.
Formik yine bize touched diye bir tanım veriyor. Bunu kullanarak o durumdanda kurtulabiliyoruz.
Yanin error altındaki alttaki kullandıklarımızdan örnek vericek olursak errors altında email varsa ve aynı zamanda
bu emaile daha önce focus olunmuşsa o zaman bu uyarıyı göster diyoruz.
HATA ÇÖZÜMÜ:
inputtan ayrıldığı anda bizim aynı handlerChange'i çalıştırdığımız gibi bide handleBlur'u çalıştırmamız lazım.
ve inputun içerisine bu inputtan ayrıldığı anda yani onBulur={email} bizim onu çalıştırmamız lazım.
*/

function Signup() {
    const { handleSubmit, handleChange, handleBlur, values, errors, touched } = useFormik({
        initialValues: {
            email: '',
            password: '',
            passwordConfirm: '',

        },
        onSubmit: (values) => {
            console.log(values);
        },
        validationSchema,
    });

    return (
        <div>
            <h1>Sign Up</h1>
            <form onSubmit={handleSubmit}>

                <label>Email</label>
                <input name='email' value={values.email} onChange={handleChange} onBlur={handleBlur} />
                { errors.email && touched.email && (<div className='error'>{errors.email}</div>)}

                <br />
                <br />

                <label>Password</label>
                <input name='password' value={values.password} onChange={handleChange} onBlur={handleBlur} />
                { errors.password && touched.password && (<div className='error'>{errors.password}</div>)}

                <br />
                <br />

                <label>Confirm Password</label>
                <input name='passwordConfirm' value={values.passwordConfirm} onChange={handleChange} onBlur={handleBlur} />
                { errors.passwordConfirm && touched.passwordConfirm && (<div className='error'>{errors.passwordConfirm}</div>)}

                <br />
                <br />


                <br />
                <br />
                <button type="submit">Submit</button>

                <br />
                <br />
                <code>{JSON.stringify(values)}</code>
            </form>
        </div>
    )
}

export default Signup

//src/components/validations.js
import * as yup from 'yup';

const validations = yup.object({
  email: yup.string().email("Geçerli bir e-mail girin.").required("Zorunlu alan."),
  password: yup.string().min(5, "Parolanız en az 5 karakter olmalıdır.").required("Zorunlu alan."),
  passwordConfirm: yup.string().oneOf([yup.ref('password')], "Yazdığınız şifreler bir biriyle uyuşmuyor.").required("Zorunlu alan.")
});
//oneOf Methodu: Bu method ile password onayının kontrolünü yapabiliyoruz.

export default validations;

Bölüm11: Memoization

  • React.memo
React.memo HK.
Bu bölümde react componentlerimizdeki gereksiz renderların önüne geçerek bu componentleri 
daha performanslı hale getirmek için uygulayabileceğimiz bağzı memoizing yöntemlerini görücez.
Bunların ilki olan React.memo ile başlıyoruz.

//Gereksiz Rendering
//src/components/Header.js
import React from 'react'

function Header() {
    console.log("Header Component Re-rendered!");
  return (
    <div>Header</div>
  )
}

export default Header

//src/App.js
import './App.css';
import {useState} from 'react';
import Header from './components/Header';
/*
Click butotuna bastığımızda header'da yeniden render ediliyor.
Biz headerda bir şey değiştirmedik bunun değişmemesi gerekmezmiydi?
Şöyle:
App.js üzerinde statemiz varya number isminde ve biz bu numberi butona bastığımızda arttırıyoruz.
Yani numberin değeri değişmiş oluyor. Bu numberin değeri değiştiği andada state değiştiği için ne oluyor?
return bölümü komple baştan render ediliyor. Peki bu return'ün içinde header'de yokmu? Evet var dolayısıyla headerda baştan render ediliyor.
İşte bu bizim için bir problem!
Bu react componentimizdeki gereksiz render anlamına geliyor. Bunun önüne geçmemiz gerekiyor.
*/
function App() {
  const [number, setNumber] = useState(0);
  return (
    <div className="App">
      <Header />
      <hr />
      <h1>{number}</h1>
      <button onClick={() => setNumber(number+1)}>Click</button>
    </div>
  );
}

export default App;

//Gereksiz renderingden kurtulmak
//src/components/Header.js
import React from 'react'

function Header() {
    console.log("Header Component Re-rendered!");
  return (
    <div>Header</div>
  )
}
/*
Bu gibi gereksiz renderlerin önüne geçmemiz durumlarında yapmamız gereken şöyle bir işlem var.
Componenti dışarı aktarırken. React.memo diyip bununla sarmalayıp aktarırsak artık öyle bir problem yaşamıyacağız!
Ve test yaptığımızda artık butona bastığımızda console logumuzda artık öyle bir log görmüyoruz.
Memo böyle gereksiz renderların önüne geçebiliyor.
*/
export default React.memo(Header)

//src/App.js
import './App.css';
import {useState} from 'react';
import Header from './components/Header';

function App() {
  const [number, setNumber] = useState(0);
  return (
    <div className="App">
      <Header />
      <hr />
      <h1>{number}</h1>
      <button onClick={() => setNumber(number+1)}>Click</button>
    </div>
  );
}

export default App;

//Re-Rendering Final
//src/components/Header.js
import React from 'react'

function Header({ number }) {
    console.log("Header Component Re-rendered!");
    return (
        <div>Header - {number}</div>
    )
}
export default React.memo(Header)

//src/App.js
import './App.css';
import {useState} from 'react';
import Header from './components/Header';
/*
Peki bu header ne zaman render edilecek? Hep böylemi kalacak.
Şöyleki bu header'a bu component'e geçtiğiniz propertyler(proplar) ne zaman değişirse işte o zaman render edilir.
Örneğin headerede numberi geçersek. Burdaki stateteki numberi prop olarak header componentimize geçelim.
Headerdede onu prop olarak alalım.
Artık butona bastığımız anda header componentin render olduğunu söylüyor her defasında oda render oluyor çünkü header componentin aldığı propertyler değişti.
Dolayısıyla render edilmesi zaten gerekiyor ve bu saatten sonra bizim için gereksiz bir render olmamış oluyor.
Farkı daha iyi anlıyabilmek için:
Bu numberi 5'den büyük olduğu zaman değiştirsek?
Örnek: number < 5 ? 0 : number
Detay: number eğer küçükse 5 den her zaman 0 göndersin değilse 5 den büyükse direkt olarak numberi göndersin istiyoruz.
O zaman bu ne demek olacak? Bu numberin değeri 5 olana kadar aslında header componenti her defasında render edilmeyecek demektir.
Ve şimdi butona ilk bastığımız zaman h1 deki number 1 olurken headerdeki 0 olarak kalacak ve dolayısıyla burası render edilmiyecek.
Şimdi 5 olduğu anda iki yerdede sayı 5 olmalı aynı zamandada consolemizde log görmeliyiz. Çünkü bu header componentin baştan render olması gerekiyor.
*/
function App() {
  const [number, setNumber] = useState(0);
  return (
    <div className="App">
      <Header number={number < 5 ? 0 : number} />
      <hr />
      <h1>{number}</h1>
      <button onClick={() => setNumber(number+1)}>Click</button>
    </div>
  );
}

export default App;
  • useMemo
useMemo HK.
//src/components/Header.js
import React from 'react'

function Header({ number, data }) {
    console.log("Header Component Re-rendered!");
    return (
        <div>Header - {number}
        <br />
        <br />
        <code>{JSON.stringify(data)}</code>
        </div>
    )
}
export default React.memo(Header)

//src/App.js
import './App.css';
import {useState} from 'react';
import Header from './components/Header';
/*
useMemo:
data adında bi obje oluşturalım. Bunu yine componentimizde karşılayalım.
Şimdi butona her bastığımızda yine baştan render ediliyor.
Şimdi demiştikki react.memo ile sarmaladığımız bi componente gönderdiğimiz proplar değişmediği sürece
o component baştan render olmaz demiştik.
Bizim burada gönderdiğimiz prop data yani içindeki name adında bir field var ve ifade ettiği değerde Emirhan aynı bir şey değişmiyor.
Peki neden? Her defasında bu component click'e tıkladığımızda render oluyor?
Şimdi şöyle bir durum var(Javascriptte şöyle bir gerçek çıkıyor karşımıza):
false denkmidir false'ye ? false === false : denktir dimi : true
true denkmidir true'ya ? true === true : denktir : true veya
5 denkmidir 5'e ? 5 === 5 : denktir : true evet
privative veri türlerinde evet böyle
eğer biz objenin başka bir objeye olan denkliğini sorgulamaya çalışırsak.
Örnek: {} === {} : false | Burada karşımıza farklı bir durum çıkıyor.
Çünkü: Şu objenin bellek üzerinde referansıyla diğer objenin bellek üzerindeki referansları farklı dolayısıyla 
Bunların denkliğini sorguladığımız zamanda karşımıza false çıktısı geliyor.
Veya bir array'i sorgulayalım. [] === [] : false | yine false çıktısını alıyoruz.
Şimdi durum böyle olunca ve ben burada butona her bastığımda setNumber çalıştığında ve numberin değeri arttığında
Bu componentin baştan render olduğunu söylemiştik. Bu baştan render olduğu içinde aslında data'da baştan hesaplanıyor.
Yani bu datanın bellek üzerindeki referansı değişiyor. Bu referans değiştiği için ve headerede prop olarak geçildiği için
React.memo gerekli sorgulamayı yapıyor. Proplar değişmişmi değişmemişmi
Şimdi burada false çıktısını aldığı içinde denk olmadığını anladığı içinde tekrardan burayıda render ediyor.
Dolayısıyla sorunumuzda bu.
Peki bundan nasıl kurtulucaz?
Yöntem 1: En basit yöntem.
Eğer bu datayı function() componentin dışında bir yerlerde yazabiliyorsak böyle yazdığımızda aslında problemden kurtulmuş olucaz.
Ve test ettiğimizde her hangi bir şey render etmiyor olduğunu görücez.
*/
//Yöntem 1:
const data = { name: "Emirhan"};

function App() {
  const [number, setNumber] = useState(0);
  
  return (
    <div className="App">
      <Header data={data} />
      <hr />
      <h1>{number}</h1>
      <button onClick={() => setNumber(number+1)}>Click</button>
    </div>
  );
}

export default App;

//useMemo Fonksiyon Oluşturup Kullanmak
//src/App.js
import './App.css';
import { useState, useMemo } from 'react';
import Header from './components/Header';
/*
useMemo Fonksiyon Oluşturup Kullanmak:
Eğer bunu yöntem-1'deki gibi yazamıyorsak illada içerde yazmamız gerekiyorsa componentin içindeki bir veriyide kullandığımız bir durum söz
konusuysa şöyle bir yönteme gitmek gerekecek. React'ın altında gelen useMemo adında hook'umuz var.
Yapmamız gereken aslında bunu kullanmak. syntax'ı useEffect gibi bir farkı yok yine oda bir dependency bir array alıyor.
Bunun içerisinde eğer return işlemini yaparsak artık tekrar tekrar header componenti render edilmemiş olacak.
Click butonuna basıyoruz ve az önceki gibi header componentimiz tekrar tekrar render olmuyor.
Peki ne zaman bu data yeniden hesaplanacak?.
Bu data ancak [] dependency arrayde belirtmiş olduğumuz veriler değiştiği anda hesaplanır.
Örneğin: Oraya number'i eklersek number her değiştiğinde return bölümü baştan hesaplanmış olacak.
Durum bu useMemo böyle bir hook. Bunu dediğimiz gibi array'ler içerisinde kullanabilirsiniz.
*/
function App() {
  const [number, setNumber] = useState(0);
  /*const data = useMemo(() => {
    return { name: "Emirhan" };
  }, []);*/
  /*const data = useMemo(() => {
    return { name: "Emirhan", number };
  }, [number]);*/
  const data = useMemo(() => {
    return calculateObject();
  }, []);
  return (
    <div className="App">
      <Header data={data} />
      <hr />
      <h1>{number}</h1>
      <button onClick={() => setNumber(number + 1)}>Click</button>
    </div>
  );
}
/* data:
Şimdi bu durum belki şuanda çokta önemsenecek bir şey değil, fakat eğer şöyle bir durum olsaydı.
Eğer bizim bir fonksiyonumuz olsaydı ve [{ name: "Emirhan", number }]; şurdaki datayı bize veriyor olsaydı.
Böyle denediğimizde yine aynı şekilde çalışmaya devam ediyor. (Render işlemi yapmadan)
*/

function calculateObject(){
  return { name: "Emirhan" };
}

export default App;

//useMemo Yanlış Kullanım Örnek
import './App.css';
import { useState, useMemo } from 'react';
import Header from './components/Header';
/*
useMemo: Yanlış Kullanım Örnek
*/
function App() {
  const [number, setNumber] = useState(0);
  const [text, setText] = useState("");
  /*const data = useMemo(() => {
    return { name: "Emirhan" };
  }, []);*/
  /*const data = useMemo(() => {
    return { name: "Emirhan", number };
  }, [number]);*/
  // const data = useMemo(() => {
  //   return calculateObject();
  // }, []);

  const data = calculateObject();
  return (
    <div className="App">
      <Header data={data} />
      <hr />
      <h1>{number}</h1>
      <button onClick={() => setNumber(number + 1)}>Click</button>
      <br />
      <br />
      <input value={text} onChange={({target}) => setText(target.value)} />
    </div>
  );
}
/* data:
Şimdi bu durum belki şuanda çokta önemsenecek bir şey değil, fakat eğer şöyle bir durum olsaydı.
Eğer bizim bir fonksiyonumuz olsaydı ve [{ name: "Emirhan", number }]; şurdaki datayı bize veriyor olsaydı.
Böyle denediğimizde yine aynı şekilde çalışmaya devam ediyor. (Render işlemi yapmadan)
*/

function calculateObject(){
  /*
  Şurada hesaplaması zor bellir bir zaman alacak tonlarca veriyle çalıştığımız bir işlem yaptıracak olsaydık.
  Örneğin:
  Hesaplamanın başlaması ve bitmesiyle ilgili log koyduk.
  Şimdi bu kodu useMemo olmadan kullansaydık.
  Butona basıyoruz.
  Calculating dedi
  Calculating complate dedi
  Şimdi bu arada belli bir süre alıyor ve biz eğer şöyle bir şey yapacak olsaydık
  Bir inputumuz olsaydı button altına yazdık <input value={text} onChange={({target}) => setText(target.value)} />
  ve tekrar bir bakalım.
  inputa bir şeyler yazmaya başlayalım. Yazdığımız anda bir hesaplama yapmaya başladı.
  Ve her bastığımızda yeniden hesaplamaya başlıyor ve burada arka arkaya yazmaya başladığımızda buradaki inputta inanılmaz bir
  Yavaşlık söz konusu oluyor. 
  Eğer biz bu hesaplama işlemini bu şekilde yaparsak ve bizim burada sadece bir inputumuz var olayı sadece içine bir veri giriliyor
  Başka bir numarası yok yani  const data = calculateObject(); şu hesaplama işlemiyle hiç bir alakası yok ama yinede 
  burdaki setText statesi değiştiği için data baştan hesaplanmak durumunda kalıyor.
  */

  console.log("Calculating...");
  for(let i=0; i<1000000000; i++) {}
  console.log("Calculating completed!");

  return { name: "Emirhan" };
}

export default App;

//useMemo Kullanımı:
import './App.css';
import { useState, useMemo } from 'react';
import Header from './components/Header';
function App() {
  const [number, setNumber] = useState(0);
  const [text, setText] = useState("");

  const data = useMemo(() => {
    return calculateObject();
  }, []);
  /*
  Yanlış örnekteki kullanmak yerine useMemo'yu kullanarak bu işlemi yapsaydık
  Her defasında o hesaplamayı yapmak durumunda kalmıyacaktık. Kontrol ettiğimizde hiç bir sıkıntı yaşamadan
  İnputumuza karakter girişi yapabiliyoruz.
  Peki bu hesaplama ne zaman yapılacak?:
  Taki useMemo'nun içerisindeki [] arrayin içerisine girdiğimiz değer artık neyse o değiştiği anda yapılacaktır.
  */
  //const data = calculateObject();
  return (
    <div className="App">
      <Header data={data} />
      <hr />
      <h1>{number}</h1>
      <button onClick={() => setNumber(number + 1)}>Click</button>
      <br />
      <br />
      <input value={text} onChange={({target}) => setText(target.value)} />
    </div>
  );
}

function calculateObject(){
  console.log("Calculating...");
  for(let i=0; i<1000000000; i++) {}
  console.log("Calculating completed!");

  return { name: "Emirhan" };
}

export default App;
  • useCallback
useCallback HK.
//src/components/Header.js
import React from 'react'

function Header({ number, increment }) {
    console.log("Header Component Re-rendered!");
    return (
        <div>Header - {number}
            <br />
            <br />
            <button onClick={increment}>Click</button>
        </div>
    )
}
export default React.memo(Header)

//src/App.js
import './App.css';
import { useState, useMemo, useCallback } from 'react';
import Header from './components/Header';
/*
useCallback:
Şöyle bir şey yapıcaz. Click butonumuzu buradan alıp. Header'e taşıyıcaz ve arttırma işlemini orda yaptırmaya çalışıcaz.
Şimdi butonu buradan alıp headere eklediğimizde setNumber işlemi headerde componentinin içinde olmadığından 
Bizim bunu header'e prop olarak göndermemiz lazım. Nasıl?
<Header increment={() => setNumber(number + 1)} /> increment olarak yazıp gönderip sonra o prop'u
Header.js içinde function içinde kullanabiliriz.
Kullandığımızda yine arttırma işlemini gerçekleştiricek. Fakat console logunda gördüğümüz gibi Header componentinin her defasında
render olduğunu görüyoruz. Neden?
Şimdi number değeri her arttığında App'in içi render oluyor. Render olduğu içinde Header componentinin increment prop'undaki 
() => setNumber(number + 1) fonksiyonda aslında baştan hesaplanıyor ve Baştan hesaplandığı içinde header componentinin içerisinde
React.memo olmasına rağmen sanki yeni bir prop varmış gibi algılanıp tekrar tekrar render ediliyor.
Bizim yapmamız gereken nedir?
increment'teki verdiğimiz fonksiyonun aslında her defasında değişmediğini aynı olduğunu bir şekilde söylemek gerekiyor.
Nasıl söyliyeceğiz?
Karşımızıda burada useCallback diye bir tanım(hook) çıkıyor.
Bu hook ile bir fonksiyon dönüyoruz ve o yaptığımız, kullandığımız veya yazdığımız fonksiyonu memoize etmiş oluyoruz.
Nereye kadar?: dependency arrayde verdiğimiz artık datalar değişene kadar o fonksiyon aynı kalıyor.
Örnek:
*/
function App() {
  const [number, setNumber] = useState(0);
  const [text, setText] = useState("");
  /*
  Örnek-1: numberi array içine vermezsek butona bastığımızda 0 dan 1 e çekecek ve tekrar her bastığımızda o değer artmıyacak.
  Sebebi: increment fonksiyonu içerisinde setNumberi kullanıyorum ve number+1 yapıyorum. Numberin ilk değeri ney? (0)
  0+1 ne = 1 ve biz bu fonksiyonu <Header increment={increment} /> buraya geçtiğimiz zaman aslında hep number'i 1 yapacak fonksiyon iletilmiş oluyor.
  Eğer array'in içerisine number'i koyarsak o zaman değer artacaktır. Çünkü: number her değiştiğinde setNumber fonksiyonu baştan hesaplanacağı için 
  Problem olmayacak ama o zamanda karşımıza başka bir problem çıkacak!
  Kullandığımızda butona bastıkmı her defasında render ediyor. 
  Bunun sebebi ney?:
  number her değiştiğinde biz setNumber fonksiyonu baştan tanımla dediğimiz için yine baştan tanımlıyo ve dolayısıyla burada yine header componentinde
  Farklı bir prop varmış gibi algılanıp baştan render ediliyor.
  O zaman biz bu dependency number'dan kurtulabilirsek aslında problemimiz çözülmüş olacak.
  Bunuda nasıl yaparız?:
  State'lere atama işlemi yaparken callback'de önceki state'yi alabiliriz.
  setNumber((prevState) => prevState + 1);
  Tekrar baktığımız zaman artık artış işlemi gerçekleşiyor. Fakat header componenti yani yukarısı tekrar tekrar render olmuyor.
  Eğer bir fonksiyonunuz varsa ve bu fonksiyonu her hangi alt bir componente geçiyorsanız ve o alt componentde tekrar tekrar render olmasını istemiyorsanız
  Çünkü bu geçtiğimiz tanımlar o fonksiyon her defasında bu component her render edildiğinde baştan hesaplanacağı için o header'da içinde react.memo olmasına rağmen
  Tekrardan render edilecektir. Bu durumlardan kurtulmak için fonksiyonlar üzerinde useCallback kullanılabilir.
  */
  const increment = useCallback(() => {
    setNumber((prevState) => prevState + 1);
  }, []);
  return (
    <div className="App">
      <Header increment={increment} />
      <hr />
      <h1>{number}</h1>

      <br />
      <br />
      <input value={text} onChange={({ target }) => setText(target.value)} />
    </div>
  );
}

export default App;

Bölüm12: Context API ile State Yönetimi

  • Context Nedir?
Context Nedir? HK.
Uygulamalarımızda her hangi bir component'te bir state oluşturduğumuzda ilgili state hep o component'in içerisinde kalıyordu veya

Bu datayı bir alt component'e göndermemiz gerekiyordu. O alt component'in altındaki bir componentte kullanmamız gerekiyorsa onunda altına tek tek eklememiz gerekiyordu.

Örnek: http://gitlab.ventura.com.tr:44852/vfw2022/react/hbys/-/wikis/uploads/4a6f750d97abb649bfa8b2a0b5e5833b/1_Jx8BCxZFN2SCuhQtZqfgMQ.jpg
Görselde sol tarafta bulunan kısma bakın.

Bu bizim için oldukça büyük bir problem ayrıca örneğin soldaki play button componenti içinde gerçekleşen var olan bir state'i ben header'da kullanmak istersem napıcam
Gibi sorunlar, sıkıntılar var.

Bunlardan tamamen kurtulmak için React bize bir kütüphane veriyor. Bir yapı veriyor. Direkt react'ın altında geliyor. Ayrıca bir kütüphane vs kurmamıza gerek yok.
İsmi: Context

Bu context'i kullanarak aslında biz elimizdeki artık o anda hangi data varsa bunu provide(sağlamak) ediyoruz.
O context'in altında kullanılmış olan tüm componentlere ve o context'in içindeki dataya her hangi bir anda her hangi bir component'in içinden erişip.
Değerini manipüle edebiliyoruz. Bu react'in bize vermiş olduğu bir araç.

State yönetimlerini yapabilmek için birden fazla araç var bugün bunlardan en bilineni en eski olanını redux, apollo client gibi bir sürü araç var. Bunların arasında baktığınız zaman kullanımı, öğrenimi en basit olanı en temiz olanı context api olarak görünüyor.
Elbet yapılan işe göre seçilecek state yönetim aracıda farklılık gösterebilir.
  • Context Oluşturmak
Context Oluşturmak
//src/context/ThemeContext.js
import { createContext } from "react";

const ThemeContext = createContext();

export default ThemeContext;

//src/App.js
import './App.css';
import Button from './components/Button';
import ThemeContext from './context/ThemeContext';

/*
Context Api ile State Yönetimi-->Context Oluşturmak:
Oluşturacağımız context'in amacı şu olacak. Bir temamız olacak lite mod ve dark mod şeklinde bunun lite veya dark mod diye değerini tutan bir context olacak ve
Bunu altında render edilmiş. Bu context'in altında render edilmiş bütün componentlerden erişip sağladığı datayı değiştirebilmek istiyoruz.
Provide: Sağlamak
Provider: Sağlayıcı
*/


function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Button />
    </ThemeContext.Provider>
  );
}

export default App;

//src/components/Button.js
import { useContext } from 'react'

import ThemeContext from '../context/ThemeContext'
//Buradaki import işlemini ve useContext işlemini hangi componentte yaparsam yapiyim o veriye erişebiliyorum demektir bu.

function Button() {
    const data = useContext(ThemeContext);
    console.log(data);
    return (
        <div>Button ({data})</div>
    )
}

export default Button

//Children Prop Kullanımı
//src/components/Button.js
import { useContext } from 'react'

import ThemeContext from '../context/ThemeContext'

function Button({children}) {
    const data = useContext(ThemeContext);
    console.log(data);
    return (
        <div>{children}</div>
    )
}

export default Button

//src/App.js
import './App.css';
import Button from './components/Button';
import ThemeContext from './context/ThemeContext';

/*
Context Api ile State Yönetimi-->Context Provider:
Provide: Sağlamak
Provider: Sağlayıcı
Context'ten sağlamış olduğumuz dataları değiştirdiğimiz anda kullanılan componentlerdede anlık olarak değiştiğini gözlemlemeye çalışacağız.
Ondan önce önceki yazdığımız provider'ımızı biraz daha yönetilebilir daha temiz bir hale getirmek için ve bu app component'ini biraz daha
Temiz bırakmak için Provider'ı ThemeContext üzerinde tanımlayabiliriz. İlla app içerisinde yapmak zorunda değiliz.
Öncesinde reactte children diye bir mantık var. <Button> Buranın içerisini istediğimiz gibi doldura biliriz. </Button>
Sonrasında Button.js' içerisine girdiğimizde function Button({children}) burada bize prop olarak children diye bir şey geliyor.
Eğer biz bu children'i kullanırsam return içerisinde App.js içerisinde butonun içine ne yazdıysam onu aslında alıp button.js'de kullanmış oluyorum.
*/

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Button>
        Merhaba,
        <p>Nulla in cupidatat eu adipisicing sunt culpa consectetur duis. Dolor amet velit est consequat veniam anim quis sit reprehenderit. Labore et minim minim mollit et consequat fugiat. Officia in incididunt enim duis ullamco labore. Cillum in veniam excepteur aliqua reprehenderit adipisicing amet amet est ea consequat veniam veniam. Laborum nulla commodo fugiat excepteur anim ut nulla cillum proident. Minim esse nulla adipisicing enim incididunt occaecat eiusmod quis est sunt aute consequat.</p>
      </Button>
    </ThemeContext.Provider>
  );
}

export default App;
  • Context Provider
Context Provider
//src/App.js
import './App.css';
import Button from './components/Button';
import { ThemeProvider } from './context/ThemeContext';
import Header from './components/Header';

/*
Context Api ile State Yönetimi-->Context Provider:
Provide: Sağlamak
Provider: Sağlayıcı
Context'ten sağlamış olduğumuz dataları değiştirdiğimiz anda kullanılan componentlerdede anlık olarak değiştiğini gözlemlemeye çalışacağız.
Ondan önce önceki yazdığımız provider'ımızı biraz daha yönetilebilir daha temiz bir hale getirmek için ve bu app component'ini biraz daha
Temiz bırakmak için Provider'ı ThemeContext üzerinde tanımlayabiliriz. İlla app içerisinde yapmak zorunda değiliz.
Öncesinde reactte children diye bir mantık var. <Button> Buranın içerisini istediğimiz gibi doldura biliriz. </Button>
Sonrasında Button.js' içerisine girdiğimizde function Button({children}) burada bize prop olarak children diye bir şey geliyor.
Eğer biz bu children'i kullanırsam return içerisinde App.js içerisinde butonun içine ne yazdıysam onu aslında alıp button.js'de kullanmış oluyorum.
//////////////////////////////////////////////////////////////////
Şimdi amacımız provider'ı context üzerine taşımak.
*/

function App() {
  return (
    //Burada ThemeProvider içine yazıcağımız ifade aslında children olmuş oluyor.
    <ThemeProvider>
      <Header />
      <hr />
      <Button />
    </ThemeProvider>
  );
}

export default App;

//src/components/Button.js
import { useContext } from 'react'

import ThemeContext from '../context/ThemeContext'

function Button() {
    //Örnek-1:
    //const data = useContext(ThemeContext);
    //console.log(data);
    //Örnek-2:
    const { theme, setTheme } = useContext(ThemeContext);
    return (
        <div>
            Active Theme: {theme}
            <br />
            <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>Change Theme</button>
        </div>
    )
}

export default Button

//src/components/Header.js
import { useContext } from 'react'

import ThemeContext from '../context/ThemeContext'

function Header() {
    const { theme, setTheme } = useContext(ThemeContext);
  return (
    <div>
        Active Theme: {theme}
        <br />
        <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>Change Theme</button>
    </div>
  )
}

export default Header

//src/context/ThemeContext.js
import { createContext, useState } from "react";

const ThemeContext = createContext();

//TheProvider diye bişiy tanımladık. Sonra bunu dışa aktardık. Neyi return ediyor? ThemeContext.Provider var ve içinde children yazıyor.
//Peki ThemeProvider dosyamızı App.js içerisine import edip içini doldurursam aslında aynı şey olmuş oluyor.
//App.js'deki ThemeProvider içinde ne varsa olduğu gibi bu Provider'ın içine gelmiş oluyor.
export const ThemeProvider = ({ children }) => {
    const [theme, setTheme] = useState("dark");
    /*
    theme'nin verisini stringini tutan statemizi ve bunu manipüle edicek olan fonksiyonumu bir şekilde Provide etmem gerekiyor.(value kısmında vermemiz lazım.)
    */
   const values = {
       theme,
       setTheme
   }
    return <ThemeContext.Provider value={values}>{children}</ThemeContext.Provider>
}

/*
Fark ne oldu?
İlgili context ile alakalı yapıcağımız her şeyi o context dosyasının içerisinde barındırmış oluyoruz.
Bir daha bu App.js içindeki App dosyamızı karmaşık hale getirmek zorunda kalmıyoruz.
Şuan 1 tane context'imiz var o kadar karışık görünmüyor olabilir ama belki onlarca context kullanıcaksınız. Öyle durumlarda
Oldukça karmaşık görünüme sebep verebilirsiniz. O yüzden böyle düzenli gitmek daha mantıklı olan.
*/

export default ThemeContext;
  • Theme Switcher Yapımı
Theme Switcher Yapımı HK.
//src/App.css
.app{
height: 100vh;
}
.app.dark {
  color: #fff;
  background-color: #282c34;
}
//src/App.js
import './App.css';
import Button from './components/Button';
import { ThemeProvider } from './context/ThemeContext';
import Header from './components/Header';
import Container from './components/Container';

/*
Context Api ile State Yönetimi-->Theme Switcher Yapımı
Provide: Sağlamak
Provider: Sağlayıcı
---------------------
Elimizdeki theme datasını kullanarak bir stillendirme yapalım.
Dark mod seçildiği anda ekran siyah olsun light mod seçildiğindede beyaz olacak şekilde.
//////////////
Şimdi bu işlemi en dıştaki divimiz üzerinden götüreceğimiz için yani dark olduğunda farklı bir className'i ve light olduğunda farklı bir className'i
İlgili div'e vermek istiyicem. Fakat bunu App.js dosyasında yapamayız. Çünkü zaten App.js dosyasında bu provider kullanılmaya başlanıyor.
Eğer bu app.js componentini sarmalayan bir yapı yoksa kullanamayız. Dolayısıyla şöyle bir şey yapabiliriz. Bir tane daha component oluştururuz.
Container.js oluştururuz. App.js içindeki yaptığımız işlemleri <header'den  almaya başlayıp container js içerisine yerleştiririz. 
Artık container componentinin içerisinde ThemeProvider'dan gelen datayı kullanabilicez.
*/

function App() {
  return (
    <ThemeProvider>
      <Container />
    </ThemeProvider>
  );
}

export default App;

//src/components/Button.js
import { useContext } from 'react'

import ThemeContext from '../context/ThemeContext'

function Button() {
    const { theme, setTheme } = useContext(ThemeContext);
    return (
        <div>
            Active Theme: {theme}
            <br />
            <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>Change Theme</button>
        </div>
    )
}

export default Button

//src/components/Container.js
import { useContext } from 'react'
import Button from './Button';
import Header from './Header';

import ThemeContext from '../context/ThemeContext'
/*
Context Api'yi kullandığımız zaman her hangi bir state'i her hangi bir başka componentte kullanmak için iç içe, alt alta ve tekrar tekrar prop olarak gönderip
Kullanmamıza gerek yok. Context denen bir yapı var. Bu yapıyı kullanarak bu işlemi çok basit bir şekilde yapabiliyoruz.
*/
function Container() {
    const { theme } = useContext(ThemeContext);
    //console.log(theme);
    return (
        <div className={`app ${theme == "dark" ? theme : ""}`}>
            <Header />
            <hr />
            <Button />
        </div>
    )
}

export default Container

//src/components/Header.js
import { useContext } from 'react'

import ThemeContext from '../context/ThemeContext'

function Header() {
    const { theme, setTheme } = useContext(ThemeContext);
    return (
        <div>
            Active Theme: {theme}
            <br />
            <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>Change Theme</button>
        </div>
    )
}

export default Header

//src/context/ThemeContext.js
import { createContext, useState } from "react";

const ThemeContext = createContext();

export const ThemeProvider = ({ children }) => {
    const [theme, setTheme] = useState("dark");
    const values = {
        theme,
        setTheme
    }
    return <ThemeContext.Provider value={values}>{children}</ThemeContext.Provider>
}

export default ThemeContext;
  • Context Provider Side Effects
Context Provider Side Effects HK.
//src/App.js
import './App.css';
import Button from './components/Button';
import { ThemeProvider } from './context/ThemeContext';
import Header from './components/Header';
import Container from './components/Container';

/*
Context Api ile State Yönetimi-->Context Provider Side Effects
Yazdığımız provider üzerinde başka neler yapabiliriz onlara bakıcaz.
Temayı değiştirdiğimiz zaman yenile yaptıkmı varsayılan olarak verdiğimiz state neyse onu gösteriyor.
Temayı değiştirdiğimiz anda gidip bunu tarayıcının local storage'sine yazsaydık ve bu provider ilk ayağa kalktığındada
Default olarak gidip o local storage'deki değere göre bunu ayağa kaldırsaydık sayfayı yenilesekte son yaptığımız değişiklik ne ise
Onu görüyor olacaktık.
*/

function App() {
  return (
    <ThemeProvider>
      <Container />
    </ThemeProvider>
  );
}

export default App;

//src/components/Container.js
import { useContext } from 'react'
import Button from './Button';
import Header from './Header';

import ThemeContext from '../context/ThemeContext'

function Container() {
    const { theme } = useContext(ThemeContext);
    //console.log(theme);
    return (
        <div className={`app ${theme == "dark" ? theme : ""}`}>
            <Header />
            <hr />
            <Button />
        </div>
    )
}

export default Container

//src/context/ThemeContext.js
import { createContext, useState, useEffect } from "react";

const ThemeContext = createContext();

//Buradaki ThemeProvider ismine aldanmayın. Aslında react componenti buda dolayısıyla react componentinde ne yapabiliyorsak o işlemleri
//Bu provider içindede yapabilirsiniz.
export const ThemeProvider = ({ children }) => {
    //Local storage'deki değeri varsayılan olarak statemize verirsek yenilediğimizde kaldığı yerden devam edecektir.
    //Local storage'de o anda bir şey yoksa light veya dark yazsın diyebiliriz.
    const [theme, setTheme] = useState(localStorage.getItem("theme") || "light");

    /*
    Bu theme her değiştiğinde bana söyle diyoruz.
    */
    useEffect(() => {
        //console.log(theme); burada kontrol ettiğimiz datayı local storagemize yazabiliriz.
        //theme parametresine , theme'yi ekliyoruz.
        //Dev Tools bölümünden Application->Local Storage bölümünden görüntüleyebiliyoruz.
        //key'imiz theme | value'miz theme = dark veya light neyse o yazılacak.
        localStorage.setItem("theme", theme);
    }, [theme]);

    const values = {
        theme,
        setTheme
    }
    return <ThemeContext.Provider value={values}>{children}</ThemeContext.Provider>
}

export default ThemeContext;
  • Multi Context
Multi Context HK.
import './App.css';
import Button from './components/Button';
import { ThemeProvider } from './context/ThemeContext';
import Header from './components/Header';
import Container from './components/Container';

import { UserProvider } from './context/UserContext';

/*
Context Api ile State Yönetimi-->Multi Context
Uygulamalarımızda birden fazla context'i barındırabiliriz.
Tek bir context hazırlayıp bütün verimizi bunun altından akıtmak zorunda değiliz.
Öyle bir şey zaten mümkünde değil aslında mümkün ama scale olabilir yapılar kurmakta oldukça zorluk çekersiniz.
Dolayısıyla bir biriyle alakasız olan tüm verileri bir birinden ayırmak. Bir biriyle alakalı olan bütün verileride
Tek bir çatı altında toplamak asıl olan bu durumda. 
Şimdi UserProvider UserContext'i ThemeContext'indeki datayıda kullanabilir durumda olmuş oluyor.
*/

function App() {
  return (
    <ThemeProvider>
      <UserProvider>
        <Container />
      </UserProvider>
    </ThemeProvider>
  );
}

export default App;

//src/components/Container.js
import { useContext } from 'react'
import Button from './Button';
import Header from './Header';

import ThemeContext from '../context/ThemeContext'
import Profile from './Profile';

function Container() {
    const { theme } = useContext(ThemeContext);
    //console.log(theme);
    return (
        <div className={`app ${theme == "dark" ? theme : ""}`}>
            <Header />
            <hr />
            <Button />
            <hr />
            <Profile />
        </div>
    )
}

export default Container

//src/components/Profile.js
import { useContext, useState } from 'react'

import UserContext from '../context/UserContext';

function Profile() {
    const { user, setUser } = useContext(UserContext);
    const [loading, setLoading] = useState(false);
    //console.log(data);
    const handleLogin = () => {
        setLoading(true);
        setTimeout(() => {
            setUser({ id:1, username: "epala", bio: "lorem ipsum"});
            setLoading(false);
        }, 1500);
    };
    const handleLogout = () => {
        setUser(null);
    };
    return (
        <div>
            {
                !user && <button onClick={handleLogin}>{loading ? "Loading..." : "Login"}</button>
            }
            <br />
            <code>{JSON.stringify(user)}</code>
            <br />
            {
                user && <button onClick={handleLogout}>Logout</button>
            }
        </div>
    )
}

export default Profile

//src/context/UserContext.js
import { createContext, useState } from "react";

const UserContext = createContext();

export const UserProvider = ({ children }) => {
    const [user, setUser] = useState(null);

    const values = { user, setUser };
    return <UserContext.Provider value={values}>{children}</UserContext.Provider>
}

export default UserContext
  • Custom Context Hook
Custom Context Hook HK.
//src/App.js
import './App.css';
import Button from './components/Button';
import { ThemeProvider } from './context/ThemeContext';
import Header from './components/Header';
import Container from './components/Container';

import { UserProvider } from './context/UserContext';

/*
Context Api ile State Yönetimi-->Custom Context Hook
Her defasında bir component'e bir context kullanıcağımız zaman örneğin: Button.js içindeki ThemeContext kullanıcağımız zaman
Önce context'in kendisini import ediyoruz. Sonra react'in altında useContext'i alıp function içinde kullanıyoruz. Bu diğer yaptıklarımız içinde geçerli.
Bu her defasında tekrar tekrar yapmak insanı yorabiliyor. Bunu biraz daha güzelleştirme şansımız var aslında. 
Şimdi bizim olayımız ney? Bir context import ediyoruz component'e yani dışa aktardığımız ThemeContext'i ilgili component'e içe aktarıyoruz.
Sonrada react'in altından useContext alıyoruz. İşte aynı işi aslında ThemeContext'in içinde yapabiliriz.
Yaptığımız bu örneklede contextlerimizi biraz daha yalınlaştırmış olduk.
*/

function App() {
  return (
    <ThemeProvider>
      <UserProvider>
        <Container />
      </UserProvider>
    </ThemeProvider>
  );
}

export default App;

//src/components/Button.js
//Artık bunada ihtiyacımız yok
//import { useContext } from 'react'

//Artık bu import işlemini yapmıyoruz.
//import ThemeContext from '../context/ThemeContext'

import {useTheme} from '../context/ThemeContext';

//Artık böyle kullanabiliriz.
function Button() {
    const { theme, setTheme } = useTheme();
    return (
        <div>
            Active Theme: {theme}
            <br />
            <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>Change Theme</button>
        </div>
    )
}

export default Button

//src/components/Container.js
import Button from './Button';
import Header from './Header';

import { useTheme } from '../context/ThemeContext'
import Profile from './Profile';

function Container() {
    const { theme } = useTheme();
    //console.log(theme);
    return (
        <div className={`app ${theme == "dark" ? theme : ""}`}>
            <Header />
            <hr />
            <Button />
            <hr />
            <Profile />
        </div>
    )
}

export default Container

//src/components/Header.js
import { useTheme } from '../context/ThemeContext'

function Header() {
    const { theme, setTheme } = useTheme();
    return (
        <div>
            Active Theme: {theme}
            <br />
            <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>Change Theme</button>
        </div>
    )
}

export default Header

//src/components/Profile.js
import { useState } from 'react'

import { useUser } from '../context/UserContext';

function Profile() {
    const { user, setUser } = useUser();
    const [loading, setLoading] = useState(false);
    //console.log(data);
    const handleLogin = () => {
        setLoading(true);
        setTimeout(() => {
            setUser({ id: 1, username: "epala", bio: "lorem ipsum" });
            setLoading(false);
        }, 1500);
    };
    const handleLogout = () => {
        setUser(null);
    };
    return (
        <div>
            {
                !user && <button onClick={handleLogin}>{loading ? "Loading..." : "Login"}</button>
            }
            <br />
            <code>{JSON.stringify(user)}</code>
            <br />
            {
                user && <button onClick={handleLogout}>Logout</button>
            }
        </div>
    )
}

export default Profile

//src/context/ThemeContext.js
import { createContext, useState, useEffect, useContext } from "react";

const ThemeContext = createContext();

const ThemeProvider = ({ children }) => {
    const [theme, setTheme] = useState(localStorage.getItem("theme") || "light");
    useEffect(() => {
        localStorage.setItem("theme", theme);
    }, [theme]);

    const values = {
        theme,
        setTheme
    }
    return <ThemeContext.Provider value={values}>{children}</ThemeContext.Provider>
}

/*
Burada kendi hook'umuzu yazalım.
useContext'i import ettik ve sonrasındada ThemeContext'i kullanmasını söylüyoruz.
Zaten biz bunu yapmıyormuyduk kullanmaya çalıştığımız componentte?
O zaman bizde diyoruzki biz bu işlemi burada yapıyoruz. Sonra bunu dışa aktarırkende sadece useTheme'i dışarı aktarabiliriz.
Onun dışında birde ThemeProvider'ı aktaralım. Manuel exportuda kaldıralım.
*/

const useTheme = () => useContext(ThemeContext);

export { useTheme, ThemeProvider };

//src/context/UserContext.js
import { createContext, useState, useContext } from "react";

const UserContext = createContext();

export const UserProvider = ({ children }) => {
    const [user, setUser] = useState(null);

    const values = { user, setUser };
    return <UserContext.Provider value={values}>{children}</UserContext.Provider>
}

export const useUser = () => useContext(UserContext);

Bölüm13: Gerçek Zamanlı Çalışan Uygulamalar Geliştirmek

  • Arayüzün Hazırlanması
  • Socket Server'a Bağlanmak
  • Backend'e Veri İletmek
  • Bir Kanala Abone Olmak

Bölüm14: Gerçek Zamanlı Chat Uygulaması

  • Giriş
  • Chat Context
  • Temel Bileşenlerin Geliştirilmesi
  • Backend Bağlantısı
  • Mesajların İletilmesi
  • Mesajların Listelenmesi
  • Feed Scroll

Bölüm15: Localization

  • React Intl - Kurulum
React Intl - Kurulum HK.
//src/App.js
import "./App.css";
import { useState } from 'react';
import { IntlProvider, FormattedMessage, FormattedNumber } from "react-intl";

/*
React ile localization işlemlerinin nasıl yapabiliriz.
Çoklu dil ile alakalı çalışmaları nasıl yönetebiliriz(yürüte biliriz) inceliyicez.
Kullanıcağımız kütüphanenin ismi: react-intl
npm i react-intl
*/

const messages = {
  "tr-TR": {
    title: "Merhaba Dünya",
    description: "3 yeni mesajınız var",
  },
  "en-US": {
    title: "Hello World",
    description: "You have 3 new messages",
  }
};

function App() {
  const [locale, setLocale] = useState("tr-TR");
  return (
    <div className="App">
      <IntlProvider messages={messages[locale]}>
        <FormattedMessage id="title" />

        <p>
          <FormattedMessage id="description" />
        </p>

        <br />
        <br />
        <button onClick={() => setLocale("tr-TR")}>TR</button>
        <button onClick={() => setLocale("en-US")}>EN</button>
      </IntlProvider>
    </div>
  );
}

export default App;
  • Default Locale
Default Locale HK.
//src/App.js
import "./App.css";
import { useState, useEffect } from 'react';
import { IntlProvider, FormattedMessage } from "react-intl";

/*
Web sitemizi ilk açtığımızda bizi türkçe içerik karşılıyor.
Sorunlar-1:
Browserimizin diline göre varsayılan olarak yazılarımızı getirtelim.
Sorunlar-2:
Sayfa yenilendiğinde en son hangi dil seçildiyse yenilendiğinde o dilden devam etmemesi.
Bu 2 sorunu çözücez.
*/

const messages = {
  "tr-TR": {
    title: "Merhaba Dünya",
    description: "3 yeni mesajınız var",
  },
  "en-US": {
    title: "Hello World",
    description: "You have 3 new messages",
  }
};

function App() {
  //local storage kayıtlı dili getirtiyoruz.
  const isLocale = localStorage.getItem("locale");
  //Tarayıcının varsayılan dilini yazdırıyoruz. navigator.language
  const defaultLocale = isLocale ? isLocale : navigator.language;
  const [locale, setLocale] = useState(defaultLocale);

  useEffect(() => {
    localStorage.setItem("locale", locale);
  }, [locale]);

  //console.log(defaultLocale);

  return (
    <div className="App">
      <IntlProvider locale={locale} messages={messages[locale]}>
        <FormattedMessage id="title" />

        <p>
          <FormattedMessage id="description" />
        </p>

        <br />
        <br />
        <button onClick={() => setLocale("tr-TR")}>TR</button>
        <button onClick={() => setLocale("en-US")}>EN</button>
      </IntlProvider>
    </div>
  );
}

export default App;
  • Parametre Geçmek
Parametre Geçmek HK.
//src/App.js
import "./App.css";
import { useState, useEffect } from 'react';
import { IntlProvider, FormattedMessage } from "react-intl";

/*
Web sitemizi ilk açtığımızda bizi türkçe içerik karşılıyor.
Sorunlar-1:
Browserimizin diline göre varsayılan olarak yazılarımızı getirtelim.
Sorunlar-2:
Sayfa yenilendiğinde en son hangi dil seçildiyse yenilendiğinde o dilden devam etmemesi.
Bu 2 sorunu çözücez.
//Mesajlarımızda data parametresi nasıl geçebiliriz?
*/

const messages = {
  "tr-TR": {
    title: "Merhaba Dünya",
    description: "{count} yeni mesajınız var",
  },
  "en-US": {
    title: "Hello World",
    description: "You have {count} new messages",
  }
};

function App() {
  //local storage kayıtlı dili getirtiyoruz.
  const isLocale = localStorage.getItem("locale");
  //Tarayıcının varsayılan dilini yazdırıyoruz. navigator.language
  const defaultLocale = isLocale ? isLocale : navigator.language;
  const [locale, setLocale] = useState(defaultLocale);

  useEffect(() => {
    localStorage.setItem("locale", locale);
  }, [locale]);

  //console.log(defaultLocale);

  return (
    <div className="App">
      <IntlProvider locale={locale} messages={messages[locale]}>
        <FormattedMessage id="title" />

        <p>
          <FormattedMessage id="description" values={{ count: 5 }} />
        </p>

        <br />
        <br />
        <button onClick={() => setLocale("tr-TR")}>TR</button>
        <button onClick={() => setLocale("en-US")}>EN</button>
      </IntlProvider>
    </div>
  );
}

export default App;

Bölüm16: Testing

  • Neden Test Yazarız?
Neden Test Yazarız? HK.
Bölüm-16: Testing

Neden test yazarız?:
Bir uygulama geliştiriyoruz. Bunun kayıt formu var, giriş formu var, giriş yapıldıktan sonra bir takım işlerde yapılmaya devam ediyor.
Bunun gibi giriş ve kayıt olma işlemi 15-20 tane daha fonksiyon (component) olduğunu düşünelim. Farklı işlemleri yapan bileşenlerin olduğunu düşünün.

Örnek:
Kayıt formunu test ettik onayladık hiç bir problem yok.

Giriş formunu yapmaya başladık bunuda test ettik onayladık bir problem yok.

x y z diye bir sürü component yapmaya devam ettik ve bizim günün sonunda projemiz bittiğinde elimizde bir sürü componentimiz olacak.
Bunların her biri başka başka işler yapıyor olacak.

Kayıt formunu hazırladığımızda gerekli kodları yazdık sonra baktık gerçekten kayıt ediyormu etmiyormu? Gerçekten kayıt ettiğini görünce ordaki işlemi tamamladığımızı düşünüp
giriş formunu yapmaya geçtik. Peki başka bir bileşeni hazırlarken eğer istemeden kayıt formuna veya giriş formuna bir zarar verdiysek onun doğru şekilde çalışmasını 
Etkileyecek bir şey yapmış olabiliriz belki bunun farkında olmaya biliriz veya son componenti yapıyoruz. Son componenti yaptığımızda gidip sistemin tamamına bakmamız lazım.
Deploy etmeden önce acaba gerçekten kayıt ediyormu?, Gerçekten giriş yapıyormu?, Giriş yaptıktan sonra x işlemini yapıyormu?, Y işlemini yapıyormu?, Z işlemini yapıyormu?
Şeklinde her birine tek tek bakmamız lazımki uygulamamızı deploy edebilelim. Bu işin manuel yöntemi. Bu manuel yapılan işlemleri biz otomatize ettirebiliriz.
Yani her bir birimin kendi içinde gerçekten doğru çalışıp çalışmadığını otomatize ettirecek kodu yazabiliriz. Dolayısıyla biz her işlem yaptıktan sonra 
Her deploy yapmadan önce gidip sistemin tamamı gerçekten çalışıyormu? Çalışmıyormu? diye kontrol etmemize gerek kalmıyacak. Bu işlemi zaten bizim için yapacak
bir kod bloğu olacak. İşte biz bu noktada ne diyoruz? Gerekli bu işlemler için bu otomasyon işlemleri için test yazmamız gerekiyor diyoruz.

Test yazmanın çeşitleri var:
Oralara girmiyicez ama biz bu işin unit test kısmında olucaz.
Yani her componentin kendi içinde, biriminde doğru çalıştığına emin olmaya çalışıcaz.

//src/App.test.js

import { render, screen } from '@testing-library/react';
import App from './App'; //Bu componentin gerçekten doğru çalışıp çalışmadığını anlamaya çalışıyor.

test('renders learn react link', () => {
  render(<App />); //App componentini render ediyor.
  const linkElement = screen.getByText(/learn react/i);
  expect(linkElement).toBeInTheDocument();
});

/*
App componentini buraya import ettikten sonra render etmiş.
Sonrada linkin burada gerçekten var olup olmadığını test etmiş.
linkElement diye bir tane sabit oluşturmuş. screen.getByText ifadesiyle o nesneyi bulmaya çalışıyor.
Yani içinde learn react geçen nesneyi bulmaya çalışıyor. Bunu bulduktan sonrada diyorki.
expect(bekliyorum) neyi bekliyorum? (linkElement) inin .toBeInTheDocument(); döküman içinde var olduğuna emin olmak istiyorum diyor.
Buradan eğer true geliyorsa testi geçtiniz diyor. Eğer false gelirse o test patlıyor. 
  • React Testing Library - 1
React Testing Library - 1 HK.
//src/App.js
import './App.css';

import Counter from './components/Counter';

function App() {
  return (
    <div className="App">
      <Counter />
    </div>
  );
}

export default App;

//src/components/Counter/index.js
import { useState } from 'react'

function Counter() {
    const [count, setCount] = useState(0);
    return (
        <div>
            <h1>{count}</h1>
            <button onClick={() => setCount(count - 1)}>Decrease</button>
            <button onClick={() => setCount(count + 1)}>Increase</button>
        </div>
    )
}

export default Counter

//src/components/Counter/Counter.test.js
/*
2 tane import işlemi yapıcaz.
1 tanesinde bir componenti render edicek.
diğerinde bir butona tıklama işlemleri yaptıracak tanımları kullanıcaz.
*/
import { render, screen } from '@testing-library/react';
//Render ile componentleri render edebiliyoruz.
//Screen ilede o anda dom'da olan her hangi bir nesneyi alabiliyoruz.
import userEvent from '@testing-library/user-event';

import Counter from './index';

//Bir test kodu yazmaya başlamak için yapılması gereken şey:
//it adında bir ifade var neden it 
/*
Test kodu yazarken butona basıldığında sayı bir artmalı
butona basıldığında bişiyler olmalı diyoruz ya
it'in anlamıda şu 
it should be a valid email address | geçerli bir email adresi olmalı diyorsunuz
it ifadesini açıklamada yazdırmaktansa bunu bir fonksiyon haline getirelim demişler aslında mantık oradan geliyor.
*/

//Örnek-1:
/*
test("increase btn", () => {
//callback yazıyoruz. Bunun içerisindede yapmak istediğimiz test otomasyonunu yazmamız gerekiyor.
render(<Counter />);
//Counter componentini render ettik ve bunun üstünde bir takım işlemler yapıcaz. Örnek: Bir butona bastırıcam. 
const count = screen.getByText("0");//İçinde 0 yazan tanımı bul dedik aslında elementi bul.
const increaseBtn = screen.getByText("Increase"); //Şuanda bu komutla ekrandaki Increase butonunu seçtik.
//Bu butona işlem yaptırmak içinde ne yapıcaz o butona tıklattırıcaz.
userEvent.click(increaseBtn); //Butona bastık şimdi bir şeyleri beklettiricez.
//Yani butona bastırdık ne olmasını bekliyoruz? Onu belirliyicez.
expect(count).toHaveTextContent("1");//Count'un değerinin 0 dan 1 olduğundan emin olalım diyicez.
//Buradaki fonksiyonlarda aslında semantic olarak isimlendirilmiş.
});
//Aynısını diğer buton için yapalım.
test("decrease btn", () => {
    render(<Counter />);
    const count = screen.getByText("0");
    const decreaseBtn = screen.getByText("Decrease"); 
    userEvent.click(decreaseBtn); 
    expect(count).toHaveTextContent("-1");
    });
*/

//Örnek-2:
describe("Counter Tests", () => {
/*
describe ifadesini kullandığımız zaman bir takım yeni yetenekler kazanıyoruz.
mesela describe içindeki bütün testler için şunu diyebiliriz.
Bütün testler çalışmadan önce yani her biri çalışmadan önce, çalıştıktan sonra veya şunları yap diyebiliriz.
*/
    let increaseBtn, decreaseBtn, count;
    beforeEach(() => {
        console.log("Her testten önce çalışacağım!");
        render(<Counter />);
        increaseBtn = screen.getByText("Increase");
        decreaseBtn = screen.getByText("Decrease");
        count = screen.getByText("0");
    })//Her biri çalışmadan önce 

    beforeAll(() => {
        console.log("İlk başta bir kere çalışacağım!");
    });//Tüm testlerden önce bir defaya mahsus çalışıyor ve sonra çalışmıyor.

    afterEach(() => {
        /* 
        Burada ne yapılabilir?
        beforeEach'te bir kayıt ekliyorsanız veritabanına afterEach ilede onu kaldırabilirsiniz.
        */
       console.log("Her testten sonra çalışacağım!");
    });//Her testten sonra çalıştırmak için kullanılır.

    afterAll(() => {
        console.log("En son bir kere çalışacağım!");
    });//Her şeyden sonra

    test("increase btn", () => {
        userEvent.click(increaseBtn);
        expect(count).toHaveTextContent("1");
    });

    test("decrease btn", () => {
        userEvent.click(decreaseBtn);
        expect(count).toHaveTextContent("-1");
    });

});
  • React Testing Library - 2
React Testing Library - 2 HK.
//src/App.js
import './App.css';

import Counter from './components/Counter';
import Todo from './components/Todo';

function App() {
  return (
    <div className="App">
      {/*<Counter />*/}
      <Todo />
    </div>
  );
}

export default App;

//src/components/Todo/Todo.test.js
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import Todo from './index';

describe("Todo Testleri", () => {
    let button,input;
    beforeEach(() => {
        render(<Todo />);

        button = screen.getByText("Add");
        input = screen.getByLabelText("Text");
    });

    test('Varsayılan olarak verilen 3 nesne render edilmeli', () => { 
        const items = screen.getAllByText(/Item/i);
        expect(items.length).toEqual(3);
     });

     test('Input ve button dökümanda bulunmalı', () => { 
        expect(button).toBeInTheDocument();
        expect(button).toBeInTheDocument();
     });

     test("Inputa string girilip butona basılınca listeye eklenmeli", () => {
         //inputu doldur
         const name = "Emirhan";
         userEvent.type(input, name);

         //butona tıkla
         userEvent.click(button);

         //assertion (kontrol ettirmek)
         expect(screen.getByText(name)).toBeInTheDocument();
     });
});

//src/components/Todo/index.js
import { useState } from 'react'

const defaultItems = [
    {
        name: "Item A"
    },
    {
        name: "Item B"
    },
    {
        name: "Item C"
    },
]

function Todo() {
    const [text, setText] = useState("");
    const [items, setItems] = useState(defaultItems);
    const addItem = () => {
        setItems(prev => [...prev, { name: text }]);
        setText("");
    };
    return (
        <div>
            <label>
                Text
                <input value={text} onChange={(e) => setText(e.target.value)} />
            </label>
            <button onClick={addItem}>Add</button>
            <br />
            <br />
            {
                items.map((item, key) => (
                    <div key={key}>{item.name}</div>
                ))
            }
        </div>
    )
}

export default Todo

Bölüm17: NPMJS Üzerinde Component Paylaşmak

  • Create-React-Library
  • Publish İşlemleri
  • Semantic Versiyonlama

Bölüm18: Deploy

  • Surge.sh
  • Netlify
  • AWS EC2 Üzerine Deploy İşlemleri

Bölüm19: E-Ticaret Uygulaması

  • Uygulama Tanitimi
  • Backend'e Genel Bakış
  • Chakra UI Kurulumu
  • Products Ekranının Hazırlanması
  • React Query
  • React Query Dev Tools
  • Ürün Detay Sayfasının Geliştirilmesi
  • useInfiniteQuery
  • Kullanımı Kayıt İşlemleri - 1
  • Kullanımı Kayıt İşlemleri - 2
  • Kullanımı Kayıt İşlemleri - 3
  • Kullanımı Kayıt İşlemleri - 4
  • Çıkış İşlemleri
  • Protected Routes
  • Login İşlemleri
  • Sepete Atma İşlemleri - 1
  • Sepete Atma İşlemleri - 2
  • Sipariş Oluşturma İşlemleri
  • Admin: Routing İşlemleri
  • Admin: Order Sayfası
  • Admin: Products Sayfası
  • Admin: Product Update İşlemleri
  • Admin: Yeni Ürün Eklemek

Bölüm20: Redux (Legacy)

  • Redux Nedir? Neden İhtiyaç Duyarız?
Redux Nedir? Neden İhtiyaç Duyarız? HK.
Redux bir javascript kütüphanesi react'in olmazsa olmazı ve bir parçası diye düşünmeyin.
Redux tamamen farklı bir javascript kütüphanesi
Javascript uygulamalarında state'i yönetmeyi sağlayan bir kütüphanedir.
React ile adının çok fazla birlikte geçiyor olmasının sebebi birlikte popüler olmaları ve birlikte entegre bir şekilde çok iyi çalışıyor olmaları.
Redux application state management olarak geçiyor literatürde yani uygulamanın durum yöneticisi olarak geçiyor diye özetleyebiliriz.
React uygulaması geliştirirken bu zamana kadar hep stateler üzerinden işlemlerimizi gerçekleştirmiştik.
Redux dediğimiz bu yapıda stateleri yönetmemizi sağlayan bir kütüphane.
Bildiğiniz gibi bizim componentlerimizin içerisinde statelerimiz bulunuyordu ve componentlerimizin sayısı arttıkça bu statelerde doğal olarak sayısal olarak
artmış oluyor ve belli bir component sayısına ulaşıldıktan sonra gerçekten bunu yönetmek çok zorlaşabiliyor. Belki ufak tefek uygulamalarda bunu fark etmemiş
olabilirsiniz bu zamana kadar ama geniş çaplı, kapsamlı bir uygulama, proje içerisine girdiğinizde bunun farkına varıyorsunuz.
İşte bu noktadada redux'ı kullanıyor olmak gerekiyor.
  • Redux Data Flow
Redux Data Flow HK.
View:
Kullanıcı web sayfasını açtı karşılaştığı ekran neyse o viewdir.

Bu ekranda bir butona bastığını farz edelim. Şöyle olsun bir tane input olsun buraya ismini yazdı ve save butonuna bastı.
Bastığı anda nolmuş oldu? Bir "Actions"(Aksiyon) gerçekleşmiş oldu.

Actions:
Burdaki kısımda napıcaz? İnputa yazmış olduğu ismi "Store"a "Dispatcher" etmemiz lazım Yani göndermemiz lazım.
Actionsda ne yapıyoruz kullanıcının yaptığı aksiyon neyse örn: Kullanıcıyı kaydetmek nedir userSave bu userSave'i ve yazmış olduğu 
isim neyse onu alıcaz ve onu alıp store'ye dispatcher edicez.
"Dispatcher" etmek demek: Actionsdaki data'yı storeye göndermek.
 
 Şimdi bu "Storeye geldikten sonra

 Store:
 İlgili yerde tek bir store var demiştik. Bunun altındada "Reducer"ler var. Bu reducer kavramıylada ilk kez karşılaşıyorsunuz.
 
 Şimdi reducer demek:
 Tek bir store var uygulamada demiştik ve bu store'da bir javascript objesiydi. 
 store = {
     user: userReducer,
     contacts: contactsReducer,
     product: productReducer
 }
 //Aslında user dediğimiz statenin karşılığı userReducer, contacts'inki contactsReducer
 Yani kullanıcıları tuttuğunuz yapı neyse ona reducer adı veriliyor ve reducerin yaptığı şöyle bir iş var.
 Store tarafından sağlanan stateyi alıyor. İlgili değişiklik neyse yapılması gereken değişiklik neyse state üzerinde o değişikliği yapıyor ve tekrardan
 state'e göndererek store'e göndererek o storeyi güncellemiş oluyor.

Kısa tekrar:
Tek bir storemiz var. Bu store altında bizim reducerlerimiz var. Bu reducerları uygulamanıza göre bölüyorsunuz bu uygulamanıza göre değişecektir.
Reducerlar store tarafından sağlanan state'i alır. İstenildiği şekilde günceller ve güncellenmiş datayı store tekrardan göndermiş olur.
Bu store üzerinde tek bir state var ve bu statede tekrardan view'a gönderilmiş olur.

Ekstra tekrar:
Bir "View"imiz var. Kullanıcı ekranı açtı ve bir "Actions" gerçekleştirdi. Bir butona bastı, bir şeye tıkladı, bir şeyler yazdı. Her hangi bir şey olabilir.
Yaptığı işlemle alakalı string datayı button click veya form submit gibi ifade bunu ve yazmış olduğu yani göndermek istediğiniz data neyse buna payload olarak adlandırıcaz
aslında onu yüklüyorsunuz ve bunu storeye "Dispatcher" ediyorsunuz. "Dispatch" etmek "Actions"u artık "Store"e gönderiyor olmak demek.
"Store" geldikten sonra bu data "Store" ilgili "Reducer"a ilgili state'i sağlıyor. Daha sonra "Reducer" bu state'i alıp.
"Actions"da göndermiş olduğumuz data göre güncelliyor ve tekrardan bunu "Store"a güncelliyen ve "Store"da güncellendikten sonra view'imizde güncellenmiş oluyor.
  • Store Oluşturmak
  • Dispatch
  • combineReducer ile Multi Reducer Kullanımı
  • Store Subscribe
  • Initial State
  • Redux Dev Tools
Redux Dev Tools HK.
Redux uygulaması geliştirirken uygulama storemizin ne durumda olduğunu aradaki bir önceki state ile bir sonraki state arasındaki farkları gibi
bir çok şeyi görebiliyoruz. "REAL TIME" olarak. O yüzden bu toolsu kullanıcaz.
  • Provider Nedir?
  • Dizin Yapısının Oluşturulması
  • Connect ile Component'e Bağlanmak
  • mapStateToProps
  • Action Dispatch Etmek
  • mapDispatchToProps
  • Component'e Props Geçmek
  • Merge Props
  • Thunk Middleware
  • Async Actions
  • Async Action Dispatch İşlemi
  • Async/Await ile Servis Çağrımı
  • Immutable vs Mutable
  • Array'i Immutable Saklamak
  • Redux Logger Middleware
  • Redux Promise Middleware

Bölüm21: React ve Redux ile Movie App Projesi (Legacy)

  • Proje Tanıtımı ve Projeyi Oluşturma
  • Proje Dizinlerinin Oluşturulması
  • Store ve Root Reducer'ı Oluşturmak
  • Redux Dev Tools & Thunk Middleware Kurulumları
  • Redux Provider
  • React Router Kurulumu
  • Movies Page Component Redux Store Bağlantısı
  • Movies List Component'inin Hazırlanması
  • Semantic UI Kurulumu
  • Semantic UI Tema Düzenlemeleri
  • Semantic UI Bug Fix - 1
  • Semantic UI Bug Fix - 2
  • Footer Component'inin Hazırlanması
  • Header Component'inin Hazırlanması
  • Semantic UI Tema Son İşlemler
  • NodeJS Backend'in Kurulması
  • mLab Düzeltme
  • Movies Action'ın Yazılması
  • Movies Reducer'ın Yazılması
  • MovieList PropType Tanımının Güncellenmesi
  • Redux Logger Kurulumu
  • Error Action Dispatch İşlemi
  • Redux Promise Middleware Kullanımı
  • Filmlerin Listelemesinin Yapılması
  • Filmlerin Listelemesinin Yapılması - 2
  • Loading Indicator
  • Routing Menüde Active Class Gösterimi
  • New Movie Sayfasının Hazırlanması
  • New Movie Form Component'inin Hazırlanması
  • New Movie Form Component'inin Hazırlanması - 2
  • New Movie Form Validasyon İşlemleri
  • New Movie Form Validasyon İşlemleri - 2
  • New Movie Sayfası Reducer Tanımının Yapılması
  • onNewMovieSubmit Action
  • onNewMovieSubmit Error Handling
  • Redirect ile Yönlendirme İşleminin Yapılması
  • Edit & Delete Butonlarının Hazırlanması
  • Movie Edit - Route İşlemleri
  • Movie Edit - Inputların Doldurulması
  • Movie Edit - Fetch Movie
  • Movie Edit - Loading Gösterimi
  • Movie Edit - Update
  • Delete Movie - 1
  • Delete Movie - 2
  • Redirect Bug Fix
  • Anasayfa Tasarımı

Bölüm22: Next.JS (Legacy)

  • Server Side Rendering Nedir?
  • Next.JS Nedir?
  • Next.JS Kurulumu
  • Pages
  • Components
  • Link
  • Routing Query String Kullanımı
  • Routing as Operatörü
  • Layout
  • Head Component'i
  • Built in CSS
  • Next.JS ve Express ile Custom Route Oluşturmak
  • Hot Module Reloading
  • Isomorphic Fetch
  • Stateful Componentlerde Isomorphic Fetch
  • Prefetch
  • onMouseEnter Prefetch
  • PWA Nedir? Service Worker Nedir?
  • Next.JS Offline
  • Now Deploy