React'a giriş temeller ile tanışma
Bu bölümde;
konularından bahsedeceğiz.
İnsanlar bir şeylere başlarken çoğu zaman neden bunu yaptığını sorgulamazlar. Onları yönlendiren belli başlı sebeplere inanırlar ve peşinden giderler. Bu sebepler; herkesin o şeyi yapıyor/kullanıyor olması olabilir, reklamının iyi yapılmış ve alternatifleri değerlendirilmeden en iyisinin o olduğuna inanmışlık olabilir. Lafına güvendiği birinin tavsiyesi olabilir ya da elindeki kaynakların ona yetmesi olabilir.
Bu yaklaşım birbirinden bağımsız bir çok konu için geçerlidir. (dizi, film, meslek seçimi, düşünce seçimi ya da kullanılan araç/alet seçimi şekilde)
Eee, bizim de konumuz bir web geliştirme aracı olan React
.
O zaman soru geliyor..
Neden React?
Aslında böyle sorular sorumak yerine direk konuya girmek, bir an evvel detaylardan bahsetmek bir çok kişinin istediği şey. Ama bu kısa girişte, yazının devamında konuşacağımız onca şeyin niye anlatıldığını sağlam bir temele oturtmak için bu girişi gerekli buluyorum.
Evet, bu soruyu ben de google amcaya sorduğumda bir çok yanıt aldım. Genelde bu yanıtlar eski bir yöntem ile -yeni diyebiliceğimiz- React'ın kıyaslaması şeklinde. Tabi bu işlerde yeni iseniz eskiden ne kullanıldığı hakkında bir bilginiz olmadığından bu kıyaslamalı örnekler sizde diğerlerine nazaran çok daha az etki gösteriyor. Direkt yenisini öğrenmek ile başlıyorsunuz. Ama yinede ufak bi kıyaslama ile React'ı diğerlerinden ayıran temel bir farka değinelim.
React bize en temelde virtual DOM diye bir kavram ile geliyor.
React hali hazırda olan DOM'un yani document object model'i daha da yanisi tarayıcıda görüğünüz sayfayı -ve onun içeriğinin- bir kopyasını Virtual DOM'da tutuyor. Bunu yapmasının sebebi ise sayfada yapılacak güncellemelerin kontrolünü sağlamak. Bu iki kopya arasında değişikleri takip edip sadece değişen kısımları ekranda da güncellemek.
Hadi bunu kısa bir demo ile görelim.
Google chrome içinde dev tools adlı bir bölüm ve onun altında sayfada gerçekleşen değişklikleri daha net görmemizi sağlayan paint flashing isimli bir seçenek var bunu açtığınızda sayfada o an neresi güncellenirse size bunu net bir şekilde gösteriyor şimdi bu araçtan faydalanıp bir demo yapacağız.
Şimdi ekrana bir buton koyup bu butona basıldığında ekrandaki 1 numarasını 2 yapan bir kod yazacağız. Bunu bi jQuery ile bir de React ile yapacağız ve Virtual DOM'un nasıl bir fayda sağladığını direk görmüş olcağız.
jQuery obje güncellendiğinde kodu
React obje güncellendiğinde kodu
Burada da gördüğünüz gibi React sayıyı 1'den 2'ye çevirdikten sonra 2 elementini tekrar güncellemiyor çünkü orada bir değişiklik yok ama jQuery'de böyle bir yapı olmadığından 1'i 2 yaptıktan sonra bile tekrar tekrar 2'yerine 2 yazmaya devam ediyor.
💡 Virtual dom arkada nasıl güncelleniyor? React değişiklikleri nasıl kıyaslıyor?
Inside Fiber: in-depth overview of the new reconciliation algorithm in React - Max Koretskyi
NOT: React örneğinde sayfanın tamamında gözüken yeşillenme sadece ilk virtual DOM oluşurken meydana geliyor.
Bu react'ın jQuery'a karşı güçlü olduğu noktaydı. Peki diğerleri yani Vue, Angular için durum nasıl.
Bu saydıklarımızdan Vue'de de Virtual DOM uygulaması bulunmakta. Ama React'ın başka özellikleri/artıları da mevcut. Bunlara yeri geldikçe değinecek olsak da şimdi bir kaç başlıkla bunlardan bahsedelim.
- JSX
- React Native
- Single-Way data flow
- Reusable Components
- Redux & Other Libraries
- Community Support & Developer Tools
Vue ile React arasındaki farklara değinen güzel bir yazıda şuarada mevcut merak edersiniz buyurun efenimm mindk.com/react-vs-vue/
Dahda fazla detay için:
Biraz da react'ın tarihçesinden bahsedelim.
React, "FaxJS" adlı ilk React prototipini yayınlayan Facebook'ta yazılım mühendisi Jordan Walke tarafından oluşturuldu. [1] [2] PHP için bir HTML component kitaplığı olan XHP'den etkilendi. İlk olarak 2011'de Facebook News Feed'de ve daha sonra 2012'de Instagram'da kullanıldı.[3] Mayıs 2013'te JSConf ABD'de açık kaynak olarak yayınlandı. [4]
Android, iOS ve UWP geliştirmeye olanak tanıyan React Native ise Şubat 2015'te Facebook'un düzenlemiş olduğu React Conf'te duyuruldu ve Mart 2015'te açık kaynaklı hale getirildi.
Facebook, 18 Nisan 2017'de kullanıcı arayüzleri oluşturmak için React Fiber adında yeni bir temel react algoritması duyurdu.
26 Eylül 2017'de React 16.0 yayınlandı.
16 Şubat 2019'da React 16.8 duyuruldu. React Hooks!
10 Ağustos 2020'de React ekibi, React geliştiriciye dönük API'de büyük değişiklikler olmaksızın ilk büyük sürüm olarak dikkat çeken React v17.0'yi duyurdu.
Bu bilgiler wikipedia react history bölümünden alınmıştır.
Component kavramı React özelinde bir konu değil. Web componentleri yıllardır var olan bir uygulama ve buna bir çok framework kütüphane içinde benzerleri ile karşılaşabilirsiniz.
Componentler ile küçük parçarlardan bir bütünü inşa ediyoruz. Ve bu tekrar kullanılabilir şekilde tasarlıyoruz. Aynı işi yapan bölümleri tek bi seferde oluşturup tekrar tekrar o parçaları kullanıyoruz. [5], [6]
React bize tekrar tekrar kullanılabilen component'leri üretmemize yardımcı olur. [7]
NOT: React içinde kullanlan componetler büyük harf ile oluşturulmalı bu şekilde html elemenlarından ayırmış oluyoruz.
İlk olarak JSX'i HTML kodları ile javascript kodlarının bir karşımı gibi düşünebilirsiniz. Ama bu doğru değil.
JSX yazarken html tag'leri kullanak sanki HTML yazdığınızı düşünseniz de yazdığınız kod bir javaScript kodu oluyor siz sadece bunu html gibi görüyorsunuz. JSX size bu ilizyonu sağlayarak javaScript ile html elemanları üretiyor.
Siz bunu yazdığınızda kodunuz arkaplanda ....
//JSX
ReactDOM.render(
<div id="test">
<h1>A title</h1>
<p>A paragraph</p>
</div>,
document.getElementById('myapp')
)
buna dönüşüyor!
// Plain JS
ReactDOM.render(
React.createElement('div', { id: 'test' },
React.createElement('h1', null, 'A title'),
React.createElement('p', null, 'A paragraph')
),
document.getElementById('myapp')
)
Bu dönüşümü sağlayan ise Babel. Projenizine Babel'i kurduktan ve ayarladıktan sonra JSX yazmanın keyfini sürebilirsiniz. Ya da create-react-app
kullanarak projenizi başlatabilir önceden hazırlanmış -babel dahil- konfügre edilmiş paketlerle çalışmaya başlayabilirsiniz.
Evet, JSX yazımı içinde yalın JS kodları çalıştırmanıza izin verir. JS çalıştırmak istediğiniz yeri süslü parantezler {}
ile çevreleyip kullanabilirsiniz.
const paragraph = 'A paragraph'
ReactDOM.render(
<table>
{rows.map((row, i) => {
return <tr>{row.text}</tr>
})}
</table>,
document.getElementById('myapp')
)
JSX'in aslında bir html kodu olmadığını sadece çevirildikten sonra bu çıktıları verdiğini konuşmuştuk. Bu yüzden html yazarken kullandığımız bazı ifadeleri JSX yazarken biraz değiştirerk yazıyoruz. Bunlardan en çok kullanları for
ile class
js için ayrılmış tanımlar (reserved words) olan bu iki ifade yerine htmlFor
ve className
ifadelerini kullanıyoruz.
ayrıca bilinmesi gereken bir ayrıntı daha var bu da componentler içinde belirtilen tüm elementler tek div içinde return edilmelidir. Eğer ifadelerinizi birden fazla div içinde hazırladıysanız React'ın Fragment özelliğini kullanabilirsiniz.
JSX için daha fazla detay için [8]
Adem İlter
'den "JSX Nedir ne değildir? Çok kısa özet! Örneklerle.." [9]
kısaltma | yatpığı iş |
---|---|
_rafce | export'lanmış arrow fonksiyonel component oluşturur (react importsuz!) |
rafce | export'lanmış arrow fonksiyonel component oluşturur (react importlu) |
rfce | export'lanmış fonksiyonel component oluşturur |
imp | import moduleName from 'module' TAB tuşu |
Ufak bir not: Aslında dokümanı okunması daha keyifli bir blog gibi hazırlamak istiyorum fakat çok fazla konuya değindiğimiz için dokümanı hazırlamak çok fazla vaktimi alıyor.
Bu şekilde devam edip hem motiasyonumu hem de vaktimi kaybetmek yerine bu noktadan sonra dokümana özet çıkartıyor gibi devam edeceğim. Konu başlığı, özet bir açıklama ve kullanım şeklinde.
Componentler arasında veri akışını sağlamak için kullanılır.
function App() {
return (
<div>
<h1>En sevdiğim meyveler </h1>
<MeyveYazar name="elma"/> {/* 🍎 "elma" burada prop olarak gönderdiğimiz değerdir. */}
</div>
)
};
function MeyveYazar(props) {
return <p>en sevdiğim meyve {props.name}</p>
};
//ya da
function MeyveYazar({ name }) {
return <p>en sevdiğim meyve { name }</p>
};
app componetimizden MeyveYazar compoentimize bu şekilde veri gönderiyoruz.
Prop'larınızın tipini ya da zorunlu olma durumlarını kontrol eder.
import PropTypes from 'prop-types';
function Greeting ({ name }){
return (
<h1>Hello, {name}</h1>
);
}
Greeting.propTypes = {
name: PropTypes.string.isRequired
};
export default Button
Varsayılan prop değerleri atamak için kullanabiliriz.
import PropTypes from "prop-types";
function Button(props) {
return <button {...props}>{props.text}</button>;
}
Button.propTypes = {
text: PropTypes.string.isRequired,
disabled: PropTypes.bool,
};
Button.defaultProps = {
text: "Click",
disabled: false,
};
export default Button;
Not: Default props'ları destruct ederken varsayılan değer olarak da tanımlayabilirdik fakat o zaman react dev tool'da hata almazdık. React dev tool bizi tarayıcı üzerinde uyarıyor.
React, how to transfer props to child components
Button elementinin içinde ne yazmış ise yazı olarak onu gönderiyor. Bu özelliği tüm elementlerde elementin içerğini göndermek için kullanabilirsiniz. [10]
function Button({children, isDisabled}) {
return (
<div>
<button disabled={isDisabled}>{children}</button>
</div>
);
}
İkişer süslü parentez kullanıyoruz.
// Result style: '10px'
<div style={{ height: 10 }}>
Hello World!
</div>
// Result style: '10%'
<div style={{ height: '10%' }}>
Hello World!
</div>
React DOM'a bastığı eleman listelerken her eleman için bir unique key vermemiz gerkeiyor. React bu şekilde DOM'a bastığı elemanları takip edebiliyor.
const todoItems = todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
);
Gönderilen tüm props'ları ifade eder. Component içinde kullanlıması gereken porp'ları destruct edip geri kalan propsları ...props olarak ifade edebiliriz.
Örnekte navigationButtonda kullanmadığımız href props'u button componet'inde kullanılmış. Altı turuncu çizili {..props}'lar ise bir sonraki component'e o componet içinde bulunan tüm props'ları aktarmak için kullanılmış.
https://reactjs.org/docs/state-and-lifecycle.html https://reactjs.org/docs/hooks-state.html
props component'ler arası veri taşımak içindi. State ise component içinde durum tutmak akışları kontrol etmek için kullanılıyor.
import React, { useState } from 'react';
function Example() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
buradaki count ve setCount state'imizi oluştururken kullandığımız tanımlayıcılar. Count direk değeri tutan değişken; setCount ise count üzerindeki değişiklikleri yapmamızı sağlayan fonksiyon. [11]
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
ayrıca functional component'ler de state kullanmadan önce setState hook'unu o dosyaya dahil etmemiz gerekiyor. default olarak export edilmediği için de süslü parantezler içinde import ediyoruz.
import React, { useState } from 'react';
Tuşa basıldığında state değiştirmek için button elementinin onClick eventine handleClick isimli bir fonksiyon yazıp setState işlemlerini onun içinde yapıyoruz.
const handleClick = (type, value) => {
if (type === "name") {
setName(value)
} else if(type === "age") {
setAge(value)
}
}
ardından bunu button'ın onClick eventine veriyoruz.
<button onClick={()=> handleClick("name", "Ayşe")}>Change name</button>
<button onClick={()=> handleClick("age", 24)}>Change age</button>
User array'ını spread operator'ü ile birlikte kopayalıyoruz ve sonra name'i yeni değeri ile güncelliyoruz.
import {useState} from "react"
function App() {
const [user, setUser] = useState({name: "Hasan", age: 22})
const handleClick = () => {
setUsers( ...user, name: "Abbas")
}
return (
<div>
{user.name} {user.age}
<hr />
<button onClick={handleClick}>Add user</button>
</div>
)
}
export default App
user isimli bir state oluşturup bu state içine iki tane user atıyoruz sonrasında bu user'lara button'a basığımızda bir yenisi eklensin istiyoruz.
import {useState} from "react"
function App() {
const [users, setUsers] = useState([
{name: "Alper", age: 23},
{name: "Hasan", age: 22}
])
const handleClick = () => {
setUsers([ ...users, {name: "Aykut", age: 22 }])
}
return (
<div>
{users.map((user, i) => (
<li key={i}>{user.name}</li>
))}
<hr />
<button onClick={handleClick}>Add user</button>
</div>
)
}
export default App
Önemli NOT:
User'ı setUser ile değil de.push
ile array'a yolladığımızda react uı'daki güncellemeyi takip edemez bu sebeple setUser'ı kullandık.
setState bir callback fonskiyon ile beraber geliyor ve bu callback içinde state'in bir önceki değeri göderiliyor. Biz bunu bir önceki örnekte olduğu gibi yeni veri ile birleştirip set edebiliriz. [12]
import {useState} from "react"
function App() {
const [users, setUsers] = useState([
{name: "Alper", age: 23},
{name: "Hasan", age: 22}
])
const handleClick = () => {
setUsers(prevState) => {
return [ ...prevState, {name: "Aykut", age: 22 }]
})
}
return (
<div>
{users.map((user, i) => (
<li key={i}>{user.name}</li>
))}
<hr />
<button onClick={handleClick}>Add user</button>
</div>
)
}
export default App
prevState kullanımı özet [12]
setState(prevState => {
// Object.assign would also work
return {...prevState, ...updatedValues};
});
Conditional Rendering [13]
return içinde block şekilde if else yazamıyoruz fakat mantıksal operatörlerle koşul işlemlerini yapabiliyoruz.
import {useState} from "react"
function App() {
const [isVisible, setIsVisible] = useState(true);
const [users, setUsers] = useState([
{name: "Alper", age: 23},
{name: "Hasan", age: 22}
])
+ const handleClick = () => {
+ setUsers(prevState) => {
+ return [ ...prevState, {name: "Aykut", age: 22 }]
+ })
+ }
const handleToggle = () => setIsVisible(!isVisible)
return (
<div>
+ <button className="aç-kapa" onClick={handleToggle}>Toggle {isVisible ? "off" : "on"}</button>
+ {isVisible && (
+ <>
+ {users.map((user, i) => (
+ <li key={i}>{user.name}</li>
+ ))}
+ <hr />
+ <button onClick={handleClick}>Add user</button>
+ </>
+ )}
</div>
)
}
export default App
aç-kapa butonuna basıldığında user'ları listeleyen yapı görünür olacak tekrar basıldığında görünmez.
aç-kapa butonuna basıldığında isVisible değeri toggle olacak.
Öncelikle inputtan alacağımız veriyi bir state'da tutmamız gerek. name adında bir state oluşturuyoruz.
import { useState } from "react";
function App() {
+ const [name, setName] = useState("");
const [users, setUsers] = useState([
{name: "Alper", age: 23},
{name: "Hasan", age: 22}
])
const handleClick = () =>
setUsers(prevState) => [ ...prevState, {name: "Aykut", age: 22 }])
+ const handleChangeName = (event) => setName(event.target.value)
return (
+ <div>
+ <input value={name} onChange={handleChangeName} />
+ <button onClick={handleClick}>Add user</button>
+ </div>
);
}
export default App;
butona bastıktan sonra input'un içini temizlemek için hadleClick içine name state'inin içini sıfırlıyoruz.
const handleClick = () => {
setUsers(prevState) => [ ...prevState, {name: "Aykut", age: 22 }])
setName("")
}
NOT: Bir inputtan veri almak için her seferinde yeni bir state mi açacağız?
- Hayır!
Form'ları daha kolay kullanmamıza yarayan paketler mevcut bunlara ilerleyen derslerde değineceğiz. Örn: Formik
Ayrıca state'ler componetler arasında çok gel git yapmaya başladığında işler çığrında çıkabiliyor. Bu durmlarda state yönetim mekanizmalarına ihtiyaç duyarız. Bunlardan en kullanışlısı contex API biraz daha karışık olarak bilinen REDUX mevcut.
..
..
..
???
https://reactjs.org/docs/hooks-intro.html , [14]
https://reactjs.org/docs/hooks-overview.html , [15]
Hooks özelliği bir herhangi bir class yazmadan fonksiyonlar yardımıyla React’teki state ve lifecycle özelliklerinin kullanılmasını sağlar. Hook’lar class’lar içerisinde çalışmadığı için fonksiyon component’ı içerisinde yer almalıdırlar. React içerisinde halihazırda yer alan temel hook’lar olarak state hook ve effect hook’u örnek verebiliriz. [16]
Hook oluştururken bazı class'ları high order componet'ler ile sarmalayıp o şekilde dışarı aktarıyoruz. Bunlara da hooks diyoruz.
Hook'lar genelde prefix olarak use ifadesini kullanır. Örn: useState, useEffect gibi..
yan etkiler
Componet'in yaşam döngüsünü (lifecycle) takip ederek olan değişiklikleri ya ilk yükleme anlarını kontrol etmemize yarar.
- Component'in DOM'a yüklendiği (mount olduğu) anı yakalayabilirim. -
componentDidMount
- Component içindeki verinin güncelendiği anı yakalayabilirim.-
componentDidUpdate
- Component'in DOM'dan kaldırıldığı (unmount) anı yakalayabilirim. -
componentWillUnmount
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// componentDidMount ve componentDidUpdate kullanımına benzer bir kullanım sunar:
useEffect(() => {
// tarayıcının başlık bölümünü değiştirmemizi sağlar
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
sayfada birden fazla defa useEffect kullanabilirsiniz.
Dependency array useEffect hook'unun isteye bağlı kullanılan ikinci argumanıdır. Adından da anlaşılacağı üzere bir önceki render'da değiştirdiğimizi array'in bağımlılığıdır. [18]
useEffect standart olarak sayfadaki tüm state güncellemelerini dinler.
function App() {
const [name, setName] = useState("Burak");
const [age, setAge] = useState(22);
useEffect(() => {
console.log("State updated");
});
return (
..
...
....
Bu örnekte name ya da age state'inde bir değişiklik olduğunda "State updated" log'unu göreceğiz. Bu useEffect'in varsayılan olarak ekrandaki tüm state'leri dinlediğini gösterir.
Eğer sadece name state'inde bir değişklik olduğunda bunu bilmek istersek; dependency array'e useEffect'in değişimini takip edeceği state'i parametre olarak vermeniz gerekir.
function App() {
const [name, setName] = useState("Burak");
const [age, setAge] = useState(22);
useEffect(() => {
console.log("name state updated");
}, [name]);
return (
..
...
....
Bu sefer useEffect sadece name state'inde bir güncelleme olduğunda çalışacak.
Eğer takip etmesin sadece mount olduğunda çalışsın istersek. Dependency array'i boş bırakabiliriz.
function App() {
const [name, setName] = useState("Burak");
const [age, setAge] = useState(22);
useEffect(() => {
console.log("App component mounted");
}, []);
return (
..
...
....
Ayrıca istersek dependency array'e birden fazla state'i argüman olarak verebilir sadece o state'leri dinlemesini sağlayabiliriz.
function App() {
const [name, setName] = useState("Burak");
const [age, setAge] = useState(22);
useEffect(() => {
console.log("age/name state updated");
}, [age, name]);
return (
..
...
....
Componet'in unmount olduğu halini de şu şekilde takip edebiliriz.
return () => console.log("App component unmounted!");
bu return'ü useEffect'in sonuna eklediğimizde unmount olduğunu anlayabiliriz.
Counter örneği;
// Counter.js
import { useState, useEffect } from "react";
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCount((n) => n + 1);
}, 1000);
return () => clearInterval(interval);
}, []);
return (
<div>
<h1>{count}</h1>
</div>
);
}
export default Counter;
// App.js
import { useEffect, useState } from "react";
import Counter from "./components/Counter";
function App() {
const [isVisible, setIsVisible] = useState(true);
return (
<div className="App">
<header className="App-header">
{isVisible && <Counter />}
<button onClick={() => setIsVisible(!isVisible)}>Toggle</button>
</header>
</div>
);
}
export default App;
Button toggle olduğunda component artık görünürlüğünü kaybediyor yani unmount oluyor. Biz de counter.js içindeki useEffect içinde componet artık unmount olduğundan onu güncellemeye devam etmek istemiyoruz bu sebeple return () => clearInterval(interval);
diyerek intervali sıfırlıyoruz. Aksi halde bunı yapmazsak react bize şu hatayı göseterecektir.
..
..
..
..
..
..
..
https://neal.fun/ Özgün hobi fikirlerinin var olduğu bir site
https://react-query.tanstack.com/ Performant and powerful data synchronization for React
- Walke, Jordan. "FaxJS". Retrieved 11 July 2019.
- Papp, Andrea (4 April 2018). "The History of React.js on a Timeline". RisingStack. Retrieved 11 July 2019.
- "Pete Hunt at TXJS"
- [JSConfUS 2013] Tom Occhino and Jordan Walke: JS Apps at Facebook
- An Introduction to Web Components, css-tricks
- Web Components MDN
- React reuseable components
- Getting started with JSX from flaviocopes
- Adem İlter'den Çok kısa özet! JSX anlatımı
- React, how to transfer props to child components
- What Do Squre brackets while creating states
- prevState
- React Conditional Rendering
- Introducing Hooks - Reactjs.org
- Hooks at a Glance - Reactjs.org
- React Hooks Nedir ve Nasıl Kullanılır? - Zafer Ayan
- useEffect örneği tr.reactjs.org
- Understanding the useEffect Dependency Array