ReactJS nedir ? Sıfırdan React…

Fatih Totrakanlı
Finartz
Published in
10 min readDec 25, 2017

Bu yazıda React’ın tarihini, yapısını, özelliklerini inceleyeceğiz ve kısa kısa örneklerle React’a basit ve anlaşılır bir giriş yapacağız.

React kendi resmi sitesinde belirtildiği üzere ‘A JavaScript library for building user interfaces’ yani ‘kullanıcı arayüzü oluşturmak için bir JavaScript kütüphanesi’ olarak tanımlanıyor.

React aslında bir zamanlar Facebook içerisinde, bir takım sorunlar için çözüm olarak sunulmuş ve Facebook geliştiricileri tarafından geliştirilen ismi koyulmamış bir kod öbeği olarak duruyor. Mark Zuckerberg’in instagramı satın almasıyla beraber hali hazırda bulunan mobil uygulamasının bir de web uygulaması olması gerekliliğine inanılıyor ve bunun için çalışmalar başlıyor. Instagram geliştiricileri Facebook’ta karşılaşılan sorunlara benzer sorunlar yaşıyorlar ve çözüm olarak Facebook’tan açık kaynak kod olacak şekilde herkesin kullanımına uygun bir kütüphane olarak sunulmasını istiyorlar. Facebook geliştiricileride bu öneri karşısında, bir kütüphane olarak React’ı çıkarıyor ve tamamen açık kaynak kodlu, herkesin erişebileceği, hala geliştirilmeye devam eden bir kütüphane olarak tüm dünyaya sunuyorlar.

Peki Facebook’un sorunu neydi de normal işleyen bir sistemden farklı bir yola girdiler ?

İçerisinde gerçek zamanlı veri akışının olduğu web sitelerini yönetmek oldukça zordur. Örneğin gerçek zamanlı bir chat aracında karşıdan size mesaj geldiğinde, gelen mesajı anlık olarak ekranınızda görmek istersiniz ve bu işlemi ekrandaki diğer görsellerin değişmeden, sadece sizin istediğiniz yerin yani mesaj gelen kısmın değişmesini isterseniz ki performanstan çok fazla kayıp yaşanmasın. Facebook’ta kendi içinde bu tarz benzer durumların önüne geçebilmek için (Facebooktaki online-offline mesajlaşma bölümü) çözüm olarak React’ı geliştiriyor ve React eski duruma göre oldukça hızlı çalışıyor hemde web sayfasını yenilemeden.

Hızı nereden geliyor ?

Tarihini bir kenara bırakıp biraz daha iç dünyasına geçme zamanı geldi. React, içerisindeki state değişikliklerinde arayüzü tekrar oluşturur. Aslında arayüzün tekrar oluşturulması bir performans kaybıdır ancak React bunu yaparken VirtualDOM adında sanal DOM mekanizması kullanır. DOM (Document Object Model) yazılım dünyasında dilleri barından bir standart olarak tanımlanır. DOM, HTML ile programlama dilleri arasında bir standart oluşturarak bu dillerin HTML den bilgi alıp, bilgi vermesine yardımcı olur. React render edilen DOM’un bir kopyasını VirtualDOM olarak tutar. İçerisinde ki herhangi bir state değişikliğinde DOM’da bir değişiklik oluyorsa sadece bu değişikliği VirtualDOM’a yansıtır ve bu durum render edilen DOM ile VirtualDOM arasında farklılık ortaya çıkarır. İşte React bu farklılıkları bularak DOM içerisinde sadece değişen alanları yeniden render eder ve bütün DOM’un tekrar render edilme masrafından kurtulmuş olur.

Nereden başlayalım ?

Özellikle hazır oluşturulan proje iskeletleriyle React ile kodlamaya başlamak çok kolay. En popüleri olan React’ın desteğini sunduğu create-react-app.

Hazır iskeleti kullanabilmek için bilgisayarınızda kurulu olarak NodeJS ve beraberinde NPM bulunması gerekiyor. Aşağıda ki komutları terminalde veya komut satırında çalıştırdığınızda benzer çıktıları görmeniz gerek.

node --version
v6.11.4
npm --version
5.4.2

Herşeyin hazır olduğunu varsayarsak aşağıda ki komutları, komut satırında veya terminalde çalıştırarak yeni bir proje oluşturabiliriz. my-app kısmının proje ismi olmasına dikkat edin.

npm install -g create-react-app
create-react-app my-app

cd my-app
npm start

Komutlar çalıştırıldıktan sonra aslında projeniz oluşturulmuş ve bir node sunucu localhost:3000 adresinden ayağa kaldırılmış olacak. Tarayıcınızı açıp bu adrese gittiğinizde ekranda React logosu ve bir takım yazılar görmüş olmalısınız. Projeyi Intellij, Webstorm vb. araçlarla açtığımızda aşağıda ki proje yapısıyla karşılaşacaksınız. Biraz da bu projenin genel yapısını inceleyelim.

my-app
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│ └── favicon.ico
│ └── index.html
│ └── manifest.json
└── src
└── App.css
└── App.js
└── App.test.js
└── index.css
└── index.js
└── logo.svg
└── registerServiceWorker.js

Projede BabelJS, Webpack, ES6, node_modules, package.json vb. bir kaç önemli bağımlılık mevcut. Konumuz React olduğu için kısa bir tanımla geçeceğiz. Bunları öğrenmek için ekstradan linkleri tanımlarıyla beraber aşağıda vereceğim.

node_modules içerisinde npm install komutuyla yüklenen paket kütüphaneler bulunmaktadır.

npm modülleri projemize dahil ederken package.json dosyasını kontrol eder. package.json, projenin ismi, versiyonu, npm komutuyla çalıştırılabilecek manuel scriptler, liste halinde verilen bağımlı olunan kütüphaneler vb. işlerin ayarlarının bulunduğu dosyadır. Örneğin npm install denildiğinde, package.json içerisindeki dependencies altında bulunan kütüphaneleri belirtilen versiyona göre yükleyip node_modules içerisine atar.

ES6 (ECMAScript 6), Javascript’in 2015 yılında belirlenen yeni standartlarını temsil eder. ES6'nın an itibari ile çoğu tarayıcı tarafından standart olarak kabul edilmediği düşünülürse, production için kullanılması biraz sorun yaratabiliyor. Bu tip durumlarda transpile eden bir ek kütüphane kullanılması gerekiyor. Babel.js ile ES6 kodlarınızı compile edebiliyorsunuz.

WebPack bir modül paketleyicisi. Script, Style, Resim dosyalarınızı tek bir bundle altında toplar. Tam olarak bir Task Manager (Grunt, Glup) olmasa da bir Task Manager’dan beklenen temel şeyleri karşılar. Javascript, CSS, png, less, sass vb. tüm dosyaları statik bir hale getirir ve tek çatı altında toplar.

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

Oluşturduğumuz projede index.js içerisinde yukarıda ki gibi bir tanım mevcut. HTML içerisinde bulunan root id’sine ait bir div’ in içerisine App isminde ki komponent mount ediliyor. Aslında bu tanım root id li div’in altında kalan herşeyin React ile çalıştırılabileceği manasına geliyor. App komponenti aslında proje içerisindeki app.js den başkası değil. Burdan anlıyoruzki React ile oluşturduğumuz her sınıf aslında bir komponent özelliği taşıyor.

Belirtmeden geçilmemesi gereken bir diğer konuda DOM özellikleri ve property’lerin camelCase yapıda olması gerekliliği. Kısa bir örnekle açıklamak gerekirse normalde htmle CSS gömmek için yazılan class property’si burada className olarak yazılıyor çünkü class rezerved bir kelime. Eğer style yazıyorsanız daha önce background-color vb. şeklinde yazdığınız kavramları backgroundColor şekline çevirmek durumundasınız çünkü javascript yazıyorsunuz ve javascriptte “-” işareti background’dan color isimli bir değişkeni çıkar anlamına gelebilir :). Aşağıda birkaç kod ve linkle bu işi bitirelim.

class -> className (CSS için, normal sınıf yapısı değil)
for -> htmlFor
background-color -> backgroundColor
margin-top -> marginTop
.
.

Render, Component, State, Props, Lifecycle kavramları nedir ?

İlk projemize detaylı olarak başlamadan önce bu kavramları öğrenmemizde yarar var. React’ta HTML, JavaScript içerisinde birlikte kodlanır. Vue.js, Angular vb. kütüphanelerde bulunan template yapısı yoktur. Dolayısıyla yazdığınız JS dosyasının herhangi bir yerinde HTML ile karşılaşabilirsiniz.

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
</div>
);
}
}

export default App;

Sınıf içinde render() fonsiyonu özel bir fonksiyondur. Sınıfın çağrıldığı yerde return içerisinde bulunan veriyi döner. Bunun dışında ki bir yerden ekrana herhangi bir veri döndürülmez. Aslında bu sınıf bizim için aynı zamanda bir komponenttir.

import React, { Component } from 'react';
import App from './App';
class Example extends Component {
render() {
return (
<div>
<App/>
<App/>
<App/>
</div>
);
}
}

export default Example;

Bu sınıfı yukarıdaki gibi herhangi bir sınıf içerisinde tekrar tekrar çağırabiliriz. Burada bize sağladığı en önemli nokta, fazla kod tekrarının önüne geçebilmesidir. Bu sayede yukarıdaki örnek için belki 30 satır kod tekrarı yapacakken komponent yapısıyla 3 satır ile hepsini çağırabiliyoruz. Bu durum bizi karmaşık bir kod öbeğinden kurtarıyor. Diğer yandan artık bizim için ‘Example’ sınıfı da bir komponenttir. Buda demek oluyor ki bu sınıfıda bir başka sınıf içerisinde çağırabilir durumdayız.

Herşey yolunda ama bir eksiklik var sanki. Sayfamızı render ettik ve sayfamızda bir görüntü görüyoruz ancak ya dinamik olarak sayfada herhangi bir yeri değiştirmek istersek ? İşte burada devreye State, Props ve ref kavramı giriyor. React, render içerisindeki herhangi bir DOM nesnesinin değiştirildiğini State’ler ile takip ediyor ve değişimi hızlı bir şekilde ekrana yansıtıyor.

import React, {Component} from 'react';
import App from "./App";

class Example extends Component {
constructor(props) {
super(props);
this.state = {
counter: 0
}
}
render() {
return (
<div>
<p>{this.state.counter}</p>
<App/>
<App/>
<App/>
<button onClick={this.onClick}>Arttır</button>
</div>
);
}

onClick = (event) => {
this.setState({counter: this.state.counter + 1});
}
}

export default Example;

Yukarıdaki kod bloğunda constructor içerisinde counter isimli bir state tanımladık. Constructor komponent yüklendiğinde bir kere çalışır ve ilk değer olarak counter isimli state’e ne değer atanmışsa onu alır. Render içerisinde bir state’in durumunu ekranda göstermek istiyorsak {this.state.counter} örneğindeki gibi yazıyoruz (aynı zamanda değişkenleri ekranda gösterirkende süslü parantez içerisinde kullanılır). Örnekte bir sayacımız var ve butona her tıklandığında 1'er arttırılıyor. Peki render fonksiyonu state’in değerinin değiştiğini nereden anlayacak ? İşte burada devreye React’ın setState fonksiyonu giriyor. Butonun onClick fonksiyonu içerisinde her tıklayışta setState çağırımıyla counter değeri 1'er arttırılıyor ve bu durum render’ın tekrar çalışmasını sağlıyor. Artık state içerisinde tutulan değer 1 arttırıldı ve ekranda görülen değer ilk tıklamayla 0'dan 1 e yükseltildi. Yukarıda ki örnekte aynı zamanda eventların kullanımınada küçük bir örnek vermiş oluyoruz. Butona’a verdiğimiz onClick fonksiyonu düz HTML de kullanıdığımız ile aynı. Bununla birlikte eskiden kullandığımız tüm eventları aynı şekilde React’ta da kullanabilir durumdayız. Dilersek eventlarla birlikte dilediğimiz değişkenleride bağlayarak gönderebiliriz. Yukarıdaki kod bloğundaki bölümleri aşağıda ki gibi değiştirdiğimizde onClick fonksiyonuna 100 değerini bağlamış oluyoruz ve her tıklamayla counter değerini 100 100 artacak şekilde değiştirmiş oluyoruz.

<button onClick={this.onClick.bind(this, 100)}>Arttır</button>onClick = (counter, event) => {
this.setState({counter: this.state.counter + counter});
}

Şimdi yukarıda yaptığımız örnekteki sayacı App komponenti içerisinde ekranda göstermeye çalışalım. Peki bu komponentin içerisindeki bir görüntüyü dışarıdan nasıl değiştireceğiz ? Bunun için React’ta Props ları kullanıyoruz. Props yardımı ile bulunduğumuz komponentten aktarmak istediğimiz herşeyi (number, string, obje, fonksiyon vb.) kullandığımız komponentlere aktarabiliriz.

import React, {Component} from 'react';
import App from "./App";

export default class Example extends Component {
constructor(props) {
super(props);
this.state = {
counter: 0
}
}
render() {
return (
<div>
<App name="Fatih" counter={this.state.counter}/>
<button onClick={this.onClick.bind(this, 100)}>Arttır</button>
</div>
);
}

onClick = (counter, event) => {
this.setState({counter: this.state.counter + counter});
}
}

App isimli komponentimize counter isminde bir property geçtik ve değer olarakta her tıklamayla değişen counter state’ini gönderdik. Render fonksiyonu her çalıştığında yeni counter değeri App komponentine gönderilecek. Bu arada prop olarak verdiğimiz counter ismi illa state ile aynı olacak diye bir durum yok. Ayşe, Fatma, Hayriye de olabilirdi :)

Peki prop olarak değeri gönderdik fakat, bu değeri App komponenti nasıl ekranda gösterecek ?

import React, { Component } from 'react';
import './App.css';

export default class App extends Component {
render() {
return (
<div className="App">
Hello {this.props.name} Your counter : {this.props.counter}
</div>
);
}
}

Başka bir yerden gelen propları {this.props} ile alıyoruz. Burada dışarıdan aldığımız name ve counter değerlerini ekranda yukarıdaki gibi gösteriyoruz.

Temel state ve prop mantığını anladıktan sonra, React’ın lifecycle’larına bir göz gezdirebiliriz. React’ın yaşam döngüsünü çeviren bir kaç tane özel fonksiyonu var. Örneğin, siz bir komponentin güncellenip güncellenmeyeceğine manuel olarak karar verebilir veya, komponent henüz sayfada yeni yükleniyorken yapacağınız işlere bir karar verebilirsiniz.

Yukarıdaki resimde gösterilen fonksiyonlar özel fonksiyonlardır ve kod içerisinde React tarafından anlaşılırlar. Örneğin bir click event’ını komponent mount edildiğinde başlatıp, unmount olduğunda silebiliriz.

import React, {Component} from 'react';
import App from "./App";

export default class Example extends Component {
constructor(props) {
super(props);
this.state = {
counter: 0
}
}
render() {
return (
<div>
<App counter={this.state.counter}/>
<button ref="myButton">Arttır</button>
</div>
);
}

increaseCounter = (e) => {
this.setState({counter: this.state.counter + 1});
}

componentDidMount() {
this.refs.myButton.addEventListener("click", this.increaseCounter);
}

componentWillUnmount() {
this.refs.myButton.removeEventListener("click", this.increaseCounter);
}
}

Önceki örneğimizi lifecycle’lara uyarlarsak komponent mount edildiğinde, yani ilk render çağırımı yapıldıktan sonra, içerisindeki myButton referanslı butona bir click event’ı ve bir fonksiyon ekledik. Bu buton, komponent yaşam döngüsünün sonuna kadar bu eventla yaşamaya devam edecek lakin, eğer komponentin kullanımından vazgeçilirse yani unmount(kullanıldığı web sayfasından farklı bir sayfaya geçmek gibi) edilirse bu butonunda click event’ına artık gerek duymayacağımız için silmemiz en doğru yöntem olacak. Tabi ki bu örnekler çoğaltılabilir ama çalışma mantığını anlamak açısından bu kadarı yeterli diye düşünüyorum.

Örneğin sizde yaptığınız uygulamada App komponentine componentWillReceiveProps lifecycle’ını ekleyerek sonuçları görebilirsiniz.

componentWillReceiveProps (nextProps) {
console.log(nextProps)
}

Listeler ve Key’ler

Web programlama yaparken bir çok iş, listelerden geçiyor. Örneğin bir serverdan aldığımız liste şeklindeki bir datayı ekranda göstermek temel amaçlarımızdan biri olsa gerek. React’ta dinamik bir <ul> <li> yapısını nasıl yapacağız diye bir soru aklınıza gelmiştir. Aslında hep JavaScript yazdığımız için, bu tür işlemleri yapmak ve modifiye etmek çok kolay. Örneğimiz üzerinde ListExample adında yeni bir komponent ekleyelim.

import React, {Component} from 'react';
import './App.css';

export default class ListExample extends Component {

mockData = [
{
name: "Fatih",
surname: "Totrakanlı"
},
{
name: "MockName",
surname: "MockSurname"
}
]

render() {
return (
<div className="App">
<ul>{this.renderList()}</ul>
</div>
);
}

renderList = () => {
let data = this.mockData;
let componentArr = [];

for(let i = 0; i < data.length; i++) {
let item = data[i];
componentArr.push(<li>{item.name + " " + item.surname}</li>)
}

return (componentArr);
}
}

Listeyi doldurmak için mock bir data oluşturduk ve onu renderList ismindeki fonksiyon içerisinde çağırdık. For döngüsü içerisinde her bir item’ı <li> tagleri arasına yerleştirip bir diziye push ediyoruz. Son olarakta bu diziyi döndürdüğümüzde ekranımızda ne kadar item varsa o kadar <li> tagıyla bölünmüş liste olacak. Yukarıdaki örnek basit bir örnek olmasına rağmen genel işleyiş hep buna benzer şekilde olacak. Dikkat edilmesi gereken bir diğer konu, yukarıdaki kod çalıştırıldığında React’ın console’da size bir uyarı vermesi olacak.

Warning: Each child in an array or iterator should have a unique “key” prop.

React tatlı tatlı diyor ki, listelerde verdiğiniz her bir child’a (bizim için <li> tag’ı) birer key verseniz ne güzel olur :). React liste içerisindeki her bir elemanı benzersiz(unique) bir key ile işaretleyerek, listenin değişmesi durumunda içerisindeki elemanların hepsini tekrardan render etmiyor, bildiği ve değişen kısımları render ediyor. Bu da demek oluyorki key vermek her zaman bizim yararımıza olacak bir yöntem :).

componentArr.push(<li key={i}>{item.name + " " + item.surname}</li>)

örneğimizi, yukarıdaki gibi güncelleyerek, her bir <li> tag’ımıza benzersiz bir key(for döngüsündeki i index’i her zaman farklı) eklemiş oluyoruz ve performansımızı daha da arttırıyoruz.

Böylelikle bu yazımızın sonuna geldik. Yazı boyunca mutlaka kaçırdığım veya atladığım noktalar olabilir. Bu yüzden tavsiyem React’ın mutlaka resmi dökümanının da üstünden geçmeniz olacaktır. Giriş aşaması için basit ve anlaşılır olması açısından, oldukça sade kodlarla anlatmaya çalıştım. Bir sonraki yazımda herkesin kullanabileceği global komponentlar nasıl yazılır, veya bir server-client haberleşmesinde React nasıl kullanılır, React-Native gibi konulara değineceğim.

Bu süreçte daha önce yazmış olduğum basit bir Rating komponenti örneğine veya client-server haberleşmesi örneğine göz gezdirebilirsiniz.

Görüşmek üzere… :).

--

--