React JS’ye Giriş

Ön yüz kütüphanesi olarak Facebook tarafından açık kaynaklı olarak geliştirilmiştir. Ön yüz bileşenlerini dinamik olarak oluşturmanıza yardımcı olur.

React JS web kullanıcı arayüzü için tasarlanmıştır. Mobil ön yüz için ise React Native kütüphanesi geliştirilmiştir. Bu yazıda size web kütüphanesinden kısaca bahsedeceğim.

MVC katmanlı uygulamayı düşündüğümüzde React’ı View katmanında kullanıyoruz. Dinamik olarak html içeriğini javascript içerisinde oluşturabiliyoruz.

React observer patterni kullanılmaktadır. Sayfanın içeriği state’lerde yapılan değişiklikler sonrasında kullanıcı arayüzü yeniden oluşturulur. Yeniden oluşturma işlemi kullanılan Virtual DOM sayesinde düşünülenin aksine performans kaybına neden olmuyor.

Virtual DOM olarak adlandırılan sanal sayfa nesne modeli (Document Object Model) içerisinde sadece state değişimleri aktarılır.  Sayfanın DOM nesnesi ile virtual DOM arasındaki farklılıklar çıkarılarak yapılacak değişiklikler hesaplanır ve sadece değişen sayfa öğeleri yeniden render edilir. Böylelikle performans artışı sağlanmış olur. Render edilirken her iki DOM birbirine eşit hale getirilir.

JSX

Javascript kodu içerisinde html kodu yazılabilmesini imkan veren syntax biçimidir. Babel gibi compiler kullanılarak JSX kodu tarayıcının anlayabileceği JS formatına çevirilmiş olur. JSX yazımı yapılırken büyük-küçük harf ve parantez veya tag kapamalarına “/>” dikkat edilmelidir.

React Component

DOM içerisinde yer alan bir react bileşenidir. İçeriğin dinamik olarak düzenlenebilmesinde adeta yapı taşıdır. İçine isterseniz div, tablo, header ekleyebilirsiniz.

 

Yeni proje için yüklenmesi gerekenler:

Node.js https://nodejs.org/en/download/

Git : https://git-scm.com/downloads

Code Editor : Sublime Text / Atom / Visual Studio Code / Brackets

 

Yeni bir React projesi oluşturup, içinde gerekli tüm node modulerinin eklenmesi için aşağıdaki komutu çalıştırırız :

> npx create –react-app sportsstore

 

Proje klasörleri:

Public :                                React dışındaki css ve html dosyalarının bulunduğu statik dosyaları içerir.

Src :                      Javascript dosyaları, uygulama css dosyaları bulunur.

 

Projeye Bootstrap CSS Fw ekleme

  1. Terminal’de komut çalıştırılarak gerekli dosyalar yüklenir:

>npm install bootstrap

  1. App.js içine aşağıdaki satır eklenir :

import  ‘bootstrap/dist/css/bootstrap.css’;

  1. Dev tool’un başlatılması için aşağıdaki komut çalıştırılır ve React uygulamamız tarayıcıdan çalıştırılabilir. İlk proje http://localhost:3000 adresinden görüntülenebilecektir.

               >npm start

Component’ler react uygulamasının en temel parçasıdır. JSX ile yazılırlar. JSX Javascript kodu içerisinde HTML kodunu ekstra alıntılamaya gerek kalmadan yazmanıza izin verir.

Render methodu kullanıcıya içeriğin görüntülenmesi için React tarafından çağırılır.

Npm start ile çalıştırmanızdan itibaren react dev tool’u otomatik olarak App.js dosyasında yaptığınız değişiklikleri algılar.

JSX içinde css elemanlarına ait class belirlemesi yapılırken className keywordü kullanılır.

Dinamik içerik göstermek:

App.js:

Constructor(props) {
	Super(props);
This.state = {
userName : “Adam”
	}
}
Render() {
	return (
	<div>
		<h4 className=”bg-primary text-white text-center p-2”>
		{ this.state.userName } ‘s To Do List
	</div>
	)
};

Constructor

Construtor component başlatıldığında çağırılan özel bir methoddur. Component’in doğru şekilde kurulmasını sağlamak için Constructor içinde super methodunun çağırılır.

Props

Props parametresi ile bir component’ten diğerini yapılandırmasını sağlar.

State

React componentlerinin durum bilgisini barındırır.

This.state = { userName : “Adam” }

This

This keyword’ü şu anda mevcut olan nesneye ve ona ait property ve methodlara erişmemizi sağlar.

State (Durum) Veri Değişiklikleri

React uygulaması state değişiklikleri üzerine kuruludur. State üzerinde değişiklik yapıldığında render methodu tekrar çağırılır. Bu nedenle ifadeler yeni state değerleri ile tekrar hesaplanır.

 

Arrow function örneği:

changeStateData = () => {
	this.setState({
		userName: this.state.userName === “Adam” ? “Bob” : “Adam”
	})
}

Render methodu içinde:

<button className=”btn btn-primary m-2” onClick={ this.changeStateData }> Change 

 

Onclick eventinde yeni eklenen methodu bu yöntemle çağırmış oluyoruz. setState methodu çağırıldığında react component state bilgilerini yenileriyle günceller ve render methodunu çağırır.

 

Arrow fonksiyonlarında return keywordü kullanılmaz veya köşeli parantez ile gövdesi belirlenmez.

Render = () => ....

<button className=”btn btn-primary m-2” onClick={ this.changeStateData }> Change 

 

Render html’de:

<input className=”form-control” value={ this.state.newItemText } 
onChange={ this.updateTextValue } />

 

event.target.value : Html input öğesinde yazılan input değerine erişmek için kullanılır.

 

Find Fonksiyonu :

array içerisinde belirli bir kritere uyan tüm öğeler üzerinde istediğiniz fonksiyonu uygulamanıza imkan verir :

createNewToDo = () => {
if(!this.state.toDoItems.find( item => item.action === this.state.newItemText ) {
	this.setState({
		todoItems : [... this.state.todoItems, 
			{action: this.state.newItemText, done : false } ],
			newItemText: “”
		});
	}
 }

 

Render html’de:

<button className=”btn btn-primary mt-1” 
onClick={ this.createNewToDo }>Add</button>

 

Filter Fonksiyonu :

Yine Render methodu içinde filter fonksiyonu sadece toDoItems arrayi içindeki tamamlanmamış öğeleri seçelim ve sonrasında onun uzunluğunu alalım :

<h4> ({ this.state.todoItems.filter (t => !t.done).length ) </h4>

 

Input elementi örneği:

Sayfaya yeni içerik eklemek için iki property si olan input elementini ekliyoruz:

Value property’si ile input içeriğini alıyoruz. Value değeri state içindeki newItemText property’sinin değerini döner. State üzerindeki herhangi bir değişiklik input elementinin içeriğini değiştirir.

onChange özelliği ise değer değişikliği olduğunda hangi fonksiyona yönlendirileceğini belirtir.

updateNewTextValue = (event) => {
	this.setState( { newItemText : event.target.value });
}

<input className=”form-control” value={ this.state.newItemText } onChange = { this.updateNewTextValue }/> 

 

Javascript spread operatörü “... “

Bir array içerisine yeni bir öğe eklemek için kullanılan notasyondur. Yeni değer eklenmeden önceki haline ifade etmede kullanılır.

	this.setState({
		todoItems : [... this.state.todoItems, 
			{action: this.state.newItemText, done : false } ],
			newItemText: “”
		});

Ekranda öğeleri listeleme

todoTableRows fonksiyonunda map methodu kullanılarak her todoItems arrayinde bulunan öğe için html sonucu dönüyor. Her öğe table row “tr” elementi ile eşleştiriliyor.

React render methodunda içeriğin ilişkilendirilebilmesi için key özelliğinin kullanılması zorunludur.

toggleToDo = (todo) => this.setState({ 
	todoItems : this.state.todoItems.map(item => item.action === todo.action ?
		{ ...item, done : !item.done } : item);

todoTableRows = () => this.state.todoItems.map(item =>
	<tr key={ item.action }>
		<td> { item.action } </td>
		<td>
			<input type=”checkbox” checked={ item.done }
			onChange={ () => this.toggleTodo (item) }  />
		</td>
	</tr> );

 

Render methodunda :

render = () =>

                              ..........

	<table className=”table table-striped table-bordered”>
	<thead>
		<tr><th>Description</th></tr>
	</thead>
	<tbody> { this.todoTableRows() } </tbody>
	</table>

Child Components

Componentleri daha yönetilebilir olması için componentlere ayırıp farklı sorumluluklar verebiliriz. Bunu child componentler ile gerçekleştiririz. Ana fonksiyon işlevleri ise parent component ile sağlanır.

Props property’sine erişmek için this keyword’ü kullanılır. “this.props.name” gibi.

Child componentler ayrı bir js dosyası içerisine yazılır. React yeni oluşturulan component’in dosyasındaki render methodunda eğer this.props.name gibi elemanlar varsa bunlara parent component içerisinde erişir.

Örnek olarak src klasörü altında TodoRow.js isimli dosya oluştururuz.

import React, { Component } from ‘react’;
export class ToDoRow extends Component {
	render = () => 
	<tr>
		<td> { this.props.item.action } </td>
		<td><input type=”checkbox” checked= { this.props.item.done }
			onChange= { () => this.props.callback( this.props.item) } /> </td>
	</tr>
}

 

Bu component tablodaki bir satırın gösterecek. ToDoRow child component ‘i props içindeki read-only  değerleri alınır. Eğer props değerlerinde değişiklik yapılmak istenirse function props kullanılarak child component içinde callback fonksiyonu çağırılarak yapılabilir. Bu sayede componentler arasında işbirlik sağlanır. Data props ile parent’tan child’a veri aktarılmış olur. Callback fonksiyonu child’ın parent ile konuşmasını sağlar.

 

Başka bir child component örneğini

import React, { Component } from ‘react’;
export class TodoCreator extends Component {
	constructor(props) {
		super(props);
		this.state  { newItemText : “” }
	}
	updateNewTextValue = (event) => {
		this.setState({ newItemText : event.target.value });
	}
	createNewToDo = () => {
		this.props.callback(this.state.newItemText);
		this.setState({ newItemText : “” });
	}
	Render = () => <div className=”my-1”>
		<input className=”form-control” value= { this.state.newItemText }
			onChange= { this.updateNewTextValue } />
		<button className=”btn btn-primary mt-1” 
			onClick= { this.createNewToDo }>Add</button>
		</div>
}

 

Child component’lerin kendine has özel state verisi bulunur. Bu da kendi içindeki input elementinin verisini yönetmesini sağlar. Ekle butonu tıklandığında function prop (this.props..) çağırılarak parent component bilgilendirilmiş olur.

 

Child Component Kullanımı

Child component’leri uygulamanın javascript dosyası içerisinde eklemek için App.js dosyasında (App componentinde)

  • import statementlar ile child component gereksinimlerini ekleriz,
  • props ve gerekli callback fonksiyonlarının da tanımlamasını yaparız.

Bir child component örneği:

 

TodoBanner.js:

import React, { Component } from ‘react’;

 export class TodoBanner extends Component {
	render = () =>
		<h4 className=”bg-primary text-white text-center p-2”>
		{ this.props.name }’s To Do List  ({ this.props.tasks.filter( 
t => !t.done).length } items to do) </h4>
}

 

App.js içindeki değişiklikler:

import { TodoCreator } from “./TodoBanner”;
import { TodoCreator } from “./TodoCreator”;
import { TodoRow } from “./TodoRow”;

export default class App extends Component {

	constructor(props) {
		super(props);
		this.state = {
			userName : “Adam”,
			todoItems : [{ action : “Buy a Mac”, done: false }, 
         { action: “Call Saul”, done: false}
			}
		}


createNewTodo = (task) => {
	if(!this.state.todoItems.find(item => item.action === task)) {
		this.setState({
			todoItems: [...this.state.todoItems, { action: task, done: false }]
		});
	}
}

toggleTodo = (todo) => this.setState({
todoItems:  this.state.todoItems
.map(item => item.action === todo.action 
? { ...item, done: !item.done } : item)
});

todoTableRows = () => 
this.state.todoItems.map(item =>
<TodoRow key={ item.action } item = { item } callback = { this.toggleTodo } />)

Render = () =>
	<TodoBanner name={ this.state.userName } tasks= {this.state.todoItems }/>
	<div className=”container-fluid”>
		<TodoCreator callback={ this.createNewTodo } />
		<table className=”table table-striped table-bordered”>
			<thead><tr><th>Description</th><th>Done</th></thead>
			<tbody> { this.todoTableRows() } </tbody>
		</table> 
	</div>

 

Parent dosyada (app.js ) verilen ifadelerle child componentlerin parent içindeki verilere erişebilmesi sağlanır.

Render methodu içinde ToDoBanner child componentine name ve task input olarak verilirken state değerleri gönderilmiş olur.

 

Props kullanarak parent’tan bilgi alınabilir, callback kullanarak parent içinden child fonksiyondan çağırım yapılabilir.

 

Bir Özellik Ekleme

To Do liste uygulamasına bitirilmiş ve bitirilmemiş olan görevleri ayrı gösterebilmesi için bir component ekleyeceğiz :

 

VisibilityControl.js

import React, { Component } from ‘react’;

export class VisibilityControl extends Component {
	render = () =>
		<div className = “form-check”>
			<input className=”form-check-input” type=”checkbox” 
				Checked = { this.props.isChecked }
				onChange = { (e) => this.props.callback(e.target.checked) } />
			<label className=”form-check-label”>
				Show { this.props.description }
			</label>
		</div>
}

 

Props kullanarak parent component’ten veri alabiliyoruz. Parent içindeki callback fonksiyonları ile uygulamamıza yeni özellikler ekleyebiliyoruz. Üstte yazılan component içerik hakkında hiçbir bilgiye sahip değil. Kullanıcı checkbox işaretlediğinde gerçekleşen change eventinde callback prop içinde belirtilen fonsiyon gerçekleşir. Callback diye isimlendiren fonksyion ana component içinde tanımlayacağız.

 

App.js içinde yaptığımız değişiklikler :

import { VisibilityControl } from “./VisibilityControl”;

this.state = {
	username : “Erdem”,
todoItems: [{ action: “speak up”, done: true },
showCompleted : true
}

todoTableRows = (doneValue) => this.state.todoItems
.filter(item => item.done === doneValue).map(item =>
	<TodoRow key={ item.action }item= { item }
		Callback={ this.toggleTodo } />)

 

Render = () =>

...............

<table className=”table table-striped table-bordered”>
	<thead><tr><th>Description</th><th>Done</th></tr></thead>
	<tbody> { this.todoTableRows(false) } </tbody>
</table>
<div className=”bg-secondary text-white text-center p-2”>
	<VisibilityControl description=”Completed Tasks” 
isChecked= {this.state.showCompleted}
callback = { (checked) => this.setState( { showCompleted : checked } ) 
} />
</div>

{	this.state.showCompleted &&	
	<table className=”table table-striped table-bordered”>
		<thead>
			<tr><th>Description</th></tr>
			<tr><th>Done</th></tr>
		</thead>
		<tbody> { this.todoTableRows(true) } </tbody>
	</table>
}

 

VisibilityControl componenti ile checkbox tıklandığında uygulamanın ana componenti içindeki showCompleted property değerinin değişiminin tetiklenmesini sağlar.

Tamamlanmış ve henüz bitmemiş olan görevleri birbirinden ayırmak için todoTableRows methoduna bir parametre ekledik ve filter methodunu kullanarak state data arrayi içindeki done değerine göre seçilmesini sağlamış olduk.

Son olarak parantez içerisinde ön koşul ve && operatörü ile sadece showCompleted değeri true iken tablo gösterilmesini belirledik.

 

Tutarlı Biçimde Tarayıcıda Veri Saklamak

Kullanıcının yaptığı seçimleri sayfayı-tarayıcıyı kapattıktan veya başka bir sayfaya geçmesinden sonra bile erişilebilir olması için Local Storage API kullanarak saklanmasını sağlayacağız. Bu işlem sunucu tarafında yapılabilir ancak farklı bir yöntem deneyelim.

 

App.js içinde method değişikliği:

createNewToDo = (task) => {
	if ( !this.state.todoItems.find( item => item.action === task) ) {
		this.setState({ todoItems: [...this.state.todoItems, { action: task, done: false }]    },
				() => localStorage.setItem(“todos”, JSON.stringify(this.state) )
			      );
	}
}

componentDidMount = () => {
	let data = localStorage.getItem(“todos”);
	this.setState(data != null ? JSON.parse(data) : 
		{
			userName : “Erdem”,
todoItems: [ { action: “Buy ETH”, done: true },
{ action: “Get it Done!”, done: true }
],
showCompleted : true
		});
}

 

Local Storage API localStroage nesnesi ile erişilebilir. setItem methodu ile örneğimizdeki görev listesini saklıyoruz. Local Storage sadece string değerleri tutabilmektedir. Bu nedenle saklanmadan önce veri nesnelerini JSON olarak serialize ediyoruz.

 

setState methodu bir fonksiyonu input parametresi olarak alabilmektedir. Böylelikle state verisi değişir değişmez bu fonksiyonda çağırılmış olur ve setItem ile en güncel veri saklanır.

 

componentDidMount methodu react’ın içinde bulunur ve component’in ilk oluşma aşamalarında çağırılır. Bu sayede veri yüklenmesi gibi görevlerde kullanılabilir.

 

Local Storage API içerisinde saklanan veriye erişmek için ise getItem methodu kullanılır. Örnekte eğer saklanan veri hiç bulunmamasında örnek data göstermek adına ilave olarak setState ile varsayılan veriler ekledik.

 

Örnek çalışmayı github sayfamdan ulaşabilirsiniz :

https://github.com/ismailsirma/React-To-Do-App

 

Share this Post

Categories

Featured Author