https://buraksenyurt.com/Burak Selim Şenyurt - React2022-04-19T04:43:12+00:00Matematik Mühendisi Bir Bilgisayar Programcısının NotlarıBurak Selim SenyurtBlogEngine.Net Syndication Generatorhttps://buraksenyurt.com/opml.axdBurak Selim SenyurtMatematik Mühendisi Bir Bilgisayar Programcısının Notlarıtr-TRBurak Selim Şenyurt0.0000000.000000https://buraksenyurt.com/post/nextjs-ile-web-api-tuketen-bir-react-uygulamasi-gelistirmekNextJS ile Web API Tüketen bir React Uygulaması Geliştirmek2020-07-18T19:22:00+00:00bsenyurt<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/24/nextjs.png" alt="" align="right" />Geçen sene React ile ilgili basit birkaç örnek denemiiş olmama rağmen öğrendiklerimi çok çabuk unuttuğumu fark ettim. Gerçek saha projelerinde sıklıkla kullanmayınca böyle bir şeyin olması kaçınılmazdı. Dolayısıyla <a href="https://github.com/buraksenyurt/skynet" target="_blank">skynet çalışmaları</a> kapsamında tekrardan pratik yapmanın uygun olacağını düşündüm. Bu sefer amacımız Star Wars için <a href="https://swapi.dev/" target="_blank">https://swapi.dev</a> adresinden sunulan REST servisini tüketen ve karakterlerin listesini gösteren bir web uygulaması geliştirmek. Bunu yaparken hafif siklet kategorisinde sayılan ancak bir çok işi kolaylaştırdığı söylenen Next.Js isimli web framework'ten faydalanacağız.</p>
<p>Örneğin dikkat çekici noktalarından birisi servisin karakter listesini sayfalama yoluyla vermesi. Yani tüm karakterleri tek seferde veren bir REST servis yerine, diğer sayfaları da ayrı HTTP Get çağrıları ile alacağımız bir yaklaşım söz konusu. Servis çağrısı sonrası elde edilen her JSON içeriğinde previous, next gibi önceki ve ileriki servis noktalarını referans eden nitelikler bulunduracağız. İşleyiş olarak sayfanın altındaki "Daha fazlası..." yazan düğmeye bastıkça yeni içerik var olanın arkasına eklenecek ve liste aşağı doğru uzayıp gidecek. Bu durumu önyüz tarafında yönetmek için çekilen içeriği ve sonraki servis adresi bağlantı bilgilerini tutmamız gerekiyor. İşte bu noktada useState, useEffect gibi enstrümanlarla React Hooks'u tanımaya çalışacağız. Ben örneğimizi Heimdall<em>(Ubuntu-20.04)</em> üstünde geliştiriyorum ancak diğer plaformlarda da benzer şekilde yazabilirsiniz. Haydi gelin idmanımıza başlayalım.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false"># Önce next.js destekli react uygulamasını oluşturalım (ben adını star-wars-peoples olarak isimlendirdim)
npx create-next-app
#Önyüz görünümünde Bootstrap bileşenlerini kullanabilmek için
npm install react-bootstrap bootstrap</pre>
<p>Kodsal değişikliklerimiz pages altındaki index.js dosyasında yer alıyor. Burayı incelemeniz konuyu anlamak adına yeterli olacaktır. Pek tabii yorum satırları en büyük yardımcınız. Bootstrap içinse sadece _app.js düzenlenmiştir.</p>
<pre class="brush:js;auto-links:false;toolbar:false" contenteditable="false">import { useState, useEffect } from 'react'; //useState ve useEffect kullanımı için eklendi
import Head from 'next/head'
import styles from '../styles/Home.module.css'
import {Card,ListGroup, Button} from 'react-bootstrap'; // Bootstrap elemanlarını kullanabilmek için ekledik
const defaultUrl=`https://swapi.dev/api/people/`; // Kullanacağımız servis adresini bir sabit değişkene aldık
/*
üstte tanımladığımızı adresi kullanarak tüm JSON verisini çeken asenkron fonksiyonumuz.
getServerSideProps, nextjs'in veri çeken fonksiyonlarından birisidir.
Farklı isimle kullanmaya çalıştığımızda çağırılmadığını görürürüz.
*/
export async function getServerSideProps(){
const response=await fetch(defaultUrl); // HTTP Get talebini gönderdik
const peoples=await response.json(); // Çekilen veri JSON formatında olduğu için, dönüştürdük
/*
component üzerinde verinin kullanılabilmesi için properties içerisine ekledik.
Bunu Home bileşeninde kullanmak için parametre olarak eklediğimize dikkat edelim.
*/
return{
props:{
peoples
}
}
}
export default function Home({peoples}) { //props ile gelen peoples parametre olarak eklendiği için içeride kullanılabilecek
// İlk denemede verinin gelip gelmediğini tespit etmek için kullanabiliriz.
// console.log('starwars-peoples',peoples); //F12 ile console penceresinden bakılabilir
// İstediğimiz bilgiler JSON verisindeki results altında duruyor. Bunları bir diziye aldık.
// Div kontrolünün içeriğini doldururken bir array'den yararlanıyoruz.
// const results=[]=peoples.results; // State kullanımına geçildiği için kapatıldı
//console.log(results);
/*
Sayfanın altında yer alan "Daha fazlası..." düğmesine basılınca var olan durumu korumayı ve üstüne yeni servis talebi ile
çektiğimiz verileri de ekleyip göstermeyi istiyoruz. Bu nedenle result, sonraki sayfa, gibi verileri güncel tutacağımız state
nesnelerini ele alacağız.
state'lerde kullanabilmek için gerekli değişkenleri, peoples ismiyle gelen JSON içeriğinden alıyoruz.
peoples getServerSideProps sayesinde zaten ilk yüklemede dolduruluyor.
swapi'deki json desenine göre içinden next ile results niteliklerini alıyoruz.
*/
const {next, results: defaultResults = [] } = peoples;
/*
results isimli bir sabit tanımladık ve bunun içeriğini updateResults ile güncelleyeceğimizi söyledik.
Varsayılan değerini de peoples isimli json nesnesinden çektiğimiz defaultResults dizisi ile doldurduk.
*/
const [results, updateResults] = useState(defaultResults);
/*
Burada da page isimli bir değişken tanımladık ve
içeriğini updatePage isimli metodla güncelleyeceğimizi söyledik.
page'in varsayılan değerini de peoples nesnesinden yakaladığımız
değerlerle doldurduk.
*/
const [page, updatePage] = useState({
next,
current: defaultUrl
});
const { current } = page;
/*
Bileşen her render edildiğinde devreye giren useEffect metodu React lifecyle sürecindeki componentDidMount, componentDidUpdate ve componentWillUnmount fonksiyonlarının görevini üstlenmekte.
Bileşen ilk yüklendiğinde loadMore olay tetiklenmesi gerçekleştiğinde devreye giriyor.
*/
useEffect(() => {
// İlk açılış sayfasındaysak varsayılan servis linki geçerlidir.
// Diğer yandan json'daki next bilgisi null ise son sayfaya gelmişizdir
// Bu iki halde return edilir.
if ( page.current === defaultUrl || !current) return;
//Bir request çağrısı aldığımızda (Örneğin loadMore tetiklendiğinde)
async function request() {
// current ile saklanan adres ne ise oradan veri çekiyoruz
const res = await fetch(current)
const data = await res.json();
// console.log('Gelen içerik->',data.results);
// console.log('data.next->',data.next);
// console.log('data.previous->',data.previous);
// console.log('current page->',page.current);
//Güncellenen state değişken verisini yenileri ile dolduruyoruz. updatePage, page sabiti ile ilintiliydi
updatePage({
next:data.next,
current,
});
// Eğer gelen json verisindeki previous değeri boşsa(yani ilk sayfadaysak)
if ( !data?.previous ) {
updateResults(data.results); //data'nın sahip olduğu varsayılan veri ile dolduruyoruz
return;
}
/*
Hali hazırda dolu olan verinin üstüne yeni servis verisini de ekliyoruz.
Liste aşağıya doğru uzayıp gidecektir böylece. Bunu sağlarken preData ile güncel data.results verisini üst üste ekledik.
data.results yeni servis çağrısı ile gelen veri, preData ise koruduğumuz veri.
*/
updateResults(preData => {
return [
...preData,
...data.results
]
});
}
request();
}, [current]);
function loadMore() {
/*
Düğmeye basılınca bu fonksiyon çalışıyor.
Fonksiyon updatePage yardımıyla page sabitinin içeriğini güncelliyor.
*/
updatePage(prePage => {
//console.log("pre nedir?->",prePage);
return {
prePage,
current: page?.next //Sonraki servis adresi verisini aldık
}
});
}
return (
<div className={styles.container}>
<Head>
<title>Star Wars İnsanları</title>
</Head>
<main className={styles.main}>
<h1 className={styles.title}>
Tüm Karakterler
</h1>
<p className={styles.description}>
Star Wars evrenindeki tüm karaktelerin temel bilgilerini bu listede bulabilirsiniz;)
</p>
<ListGroup>
{results.map(r=>{
const {name,birth_year,height}=r;
return(
<Card styles={{width:'18rem'}}>
<Card.Body>
<Card.Title>
{name}
</Card.Title>
<Card.Text>
{name}, {birth_year} yılında doğmuştur. Boyu {height} cm'dir.
</Card.Text>
</Card.Body>
</Card>
)
})}
</ListGroup>
<div>
<Button styles="btn btn-primary" onClick={loadMore}>Daha fazlası...</Button>
</div>
</main>
<footer className={styles.footer}>
<a
href="https://swapi.dev/"
target="_blank"
rel="noopener noreferrer"
>Diğer API Hizmetleri için tıklayın.
</a>
</footer>
</div>
)
}</pre>
<h2>Çalışma Zamanı</h2>
<p>Index sayfasını tamamladıktan sonra terminal'den aşağıdaki komutu verip sonrasında localhost:3000 adresini ziyaret etmemiz yeterli.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">npm run dev</pre>
<p>Ve çalışma zamanına ait bir görüntü.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/24/Screenshot_1.png" alt="" /></p>
<p>Kodları denerken yorum satırı olan console.log satırlarını açmanız işe yarayabilir. F12 Developers Tools sekmesinde bu sayede akan mesajları da görebilirsiniz. Tabii uygulamada ufak bir problemimiz de var. Minik bir bug diyelim :D "Daha fazlası..." butonuna bastıkça listemiz açılıyor ancak bir önceki konuma dönmemiz mümkün olmuyor. Söz gelimi "Azalt..." isimli bir button daha olsa ve buna basılınca state bir önceki konumuna dönse hiç fena olmaz. Sizce bunu yapmak mümkün mü? Eğer mümkün olduğunu düşünüyorsanız lütfen yorumlarda belirtip bana yardımcı olun ;) Böylece geldik bir skynet derlemesinin daha sonuna. Kaynak kodlara <a href="https://github.com/buraksenyurt/skynet/tree/master/No%2024%20-%20A%20Simple%20React%20App%20with%20NextJS" target="_blank">github reposu üzerinden</a> erişebilirsiniz. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>2020-07-18T19:22:00+00:00nextjsreactrestrest apirest based servicesweb frameworkreact hooksbsenyurtGeçen sene React ile ilgili basit birkaç örnek denemiiş olmama rağmen öğrendiklerimi çok çabuk unuttuğumu fark ettim. Gerçek saha projelerinde sıklıkla kullanmayınca böyle bir şeyin olması kaçınılmazdı. Dolayısıyla skynet çalışmaları kapsamında tekrardan pratik yapmanın uygun olacağını düşündüm. Bu sefer amacımız Star Wars için https://swapi.dev adresinden sunulan REST servisini tüketen ve karakterlerin listesini gösteren bir web uygulaması geliştirmek. Bunu yaparken hafif siklet kategorisinde sayılan ancak bir çok işi kolaylaştırdığı söylenen Next.Js isimli web framework'ten faydalanacağız.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=e280fe1a-9237-4721-bd3f-b29a355842f00https://buraksenyurt.com/trackback.axd?id=e280fe1a-9237-4721-bd3f-b29a355842f0https://buraksenyurt.com/post/nextjs-ile-web-api-tuketen-bir-react-uygulamasi-gelistirmek#commenthttps://buraksenyurt.com/syndication.axd?post=e280fe1a-9237-4721-bd3f-b29a355842f0https://buraksenyurt.com/post/bir-react-uygulamasinda-en-ala-sql-veritabanini-kullanmakBir React Uygulamasında En Ala SQL Veritabanını Kullanmak2019-11-11T10:30:00+00:00bsenyurt<p><img style="float: right;" src="https://buraksenyurt.com/image.axd?picture=/2019/09/25/wcraft.jpg" alt="" />İngilizcede bazen gemi kaptanlarına Captain yerine Skipper dendiğini biliyor muydunuz? Aslında Hollandalıların schipper, schip en nihayetinde de ship kelimelerinden türeyerek gelmiş bir ifade. Her ikisi de kaptanı ifade etmekte ama Skipper daha çok bir hitap şekli. Hatta yer yer takım kaptanları veya uçak pilotları için de kullanılıyor. Skipper kelimesinin kullanıldığı yerleri düşününce aklıma The Hunt For Red October filminde USS Dallas kaptanı Mancuso'nun CIA'den Jack Ryan'a "That's right? Skipper's Ramius?" demesi geliyor.</p>
<p>Esasında bu hitap şeklinin bana anımsattığı daha güzel şeyler var. Blizzard geliştiricilerinin Warcraft II'sini oynadığım zamanlarda insan kuvvetlerindeki gemilere Skipper diye sesleniliyordu. Karakterlerin o müthiş ses efektleri hala aklımda. "Ay ay sör", "Ayy keptın", "Set seyıl", "Sıkipp?", "Andır veyy!" :D Yazılı olarak seslendirmeye çalıştım ama dinleseniz çok daha iyi olabilir. Diğer pek çok karakterin sesi de harikaydı. Mesela köylülerin "Yeş mi lord" diyişindeki şirinlik ya da okçuların tonlamasındaki keskinlik. Youtube'dan silinene kadar <a href="https://www.youtube.com/watch?v=6wkc4uCaLpw" target="_blank">şu adresten dinleyebilir</a> veya aratabilirsiniz. Bugünkü konumuza gündem olmasının sebebi ise skipper isimli bir nesne dizisini kullanacak olmamız. Öyleyse başlayalım.</p>
<p>Öğrenecek bir çok şeyler araştırırken<em>(ki samimi olmak gerekirse 24 saat uykusuz kalıp bir şeyleri öğrensek bile zamanın yetmeyeceği ve güneşe daha uzak bir gezegende yaşamamız gerektiği ortaya çıkıyor)</em> <a href="http://alasql.org/" target="_blank">AlaSQL</a> isimli bir çalışma ile karşılaştım. Tarayıcı üzerinde çalışabilen istemci taraflı bir In-Memory veritabanı olarak geçiyor. Tamamen saf Javascript ile yazılmış. Geleneksel ilişkisel veritabanı özelliklerinin çoğunu barındırıyor. Group, join, union gibi fonksiyonellikleri karşılıyor. In-Memory tutulan veriyi kalıcı olarak saklamakta mümkün. Hatta bu noktada localStorage olarak ifade edilen yerel depolama alanlarından veri okunup tekrar yazılabiliyor. IndexedDB veya Excel gibi ürünleri fiziki repository olarak kullanabiliyor. Ayrıca JSON nesnelerle çalışabiliyoruz ki bu da NoSQL desteği anlamına gelmekte. Bu nedenle SQL ve NoSQL rahatlığını bir arada sunan hafif bir veritabanı gibi düşünülebilir.</p>
<p>Açık kaynak kodlu, dokümantasyonu oldukça zengin bir proje. Yine de endüstriyel anlamda olgunlaştığına dair emareler görülmeden canlı ortamlarda kullanmak riskli olabilir diye düşünürken github projesinden çıkıp org alan adına geçerek biraz daha ciddiye alınmaya başladığını fark ettim. Yine de deneysel çalışmalarda ele almakta yarar var. Benim <a href="https://github.com/buraksenyurt/saturday-night-works/tree/master/No%2025%20-%20AlaSQL%20on%20React" target="_blank">25nci cumartesi gecesi çalışması</a>ndaki amacım onu yalın bir React uygulamasında deneyimlemeye çalışmaktı. Öyleyse gelin notlarımızı toparlamaya başlayalım.</p>
<h2>Kurulum ve Hazırlıklar</h2>
<p>Ben her zaman olduğu gibi örneğimi WestWorld<em>(Ubuntu 18.04, 64bit)</em> üzerinde deneyimledim. Ancak komutlar plaform bağımsız olarak ele alınabilir. Ah bu arada sisteminizde node'un yüklü olduğunu varsayıyorum. React uygulamasını kolayca oluşturabilmek için aşağıdaki terminal komutunu kullanabiliriz.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">npx create-react-app submarine</pre>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2019/09/25/credit_1.png" alt="" /></p>
<p>AlaSQL'i kullanabilmek içinse uygulama klasöründe gerekli npm paketinin yüklenmesi yeterli olacaktır. Ayrıca görselliği zenginleştirmek için ben Bootstrap'i kullanmayı tercih ettim.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">cd submarine
npm install --save-dev alasql bootstrap</pre>
<p>React şablonu aslında senaryomuzdan bağımsız bir çok gereksiz dosya içerebilir. Bunları silip manifest.json içeriğini bir parça değiştirebiliriz. Örneğin uygulamanın tanımlayıcısı olan short_name ve name değerlerini aşağıdaki hale getirebiliriz.</p>
<pre class="brush:js;auto-links:false;toolbar:false" contenteditable="false">{
"short_name": "Tac-War-Mag",
"name": "Tactical World Magazine",
// diğer kısımlar</pre>
<p>Pek tabii en önemli kısım App.js dosyasında yapılanlar. Burası uygulamanın ayağa kalktıktan sonra oluşturulan ana bileşeni<em>(component)</em> Ana sayfanın HTML içeriği ile birlikte SQL ilişkili kodlarını barındırmakta. Ben mümkün mertebe içeriği yorum satırları ile zenginleştirerek açıklamaya çalıştım.</p>
<pre class="brush:html;auto-links:false;toolbar:false" contenteditable="false">import React, { Component } from 'react';
import 'bootstrap/dist/css/bootstrap.css'; // az biraz bootstrap ile görselliği düzeltelim
import * as alasql from 'alasql'; // alasql ile konuşmamızı sağlayacak modül bildirimimiz
class App extends Component {
/* yapıcı metod gibi düşünebiliriz sanırım
genellikle local state değişkenlerini başlatmak ve onlara değer atamak
için kullanılır
*/
constructor(props) {
super(props);
/*
state'i değişebilir veriler için kullanırız. state değişikliğinde
bileşenin otomatik olarak yeniden render edilmesi söz konusu olur
*/
this.state = { skippers: [] };
}
/*
componentWillMount metodu, ilgili bileşen Document Object Model'e bağlanmadan
önce çalışır.
Bizim örneğimizde veritabanını ve tablo kontrolünün yapılması ve
yoklarsa yaratılmaları için ideal bir yerdir
*/
componentWillMount() {
/*
Klasik SQL ifadeleri ile TacticalWorldDb isimli bir veritabanı olup
olmadığını kontrol ediyor ve eğer yoksa oluşturup onu kullanacağımızı belirtiyoruz.
SQL ifadelerini çalıştırmak için alasql metodunu çağırmak yeterli.
*/
alasql(`
CREATE LOCALSTORAGE DATABASE IF NOT EXISTS TacticalWorldDb;
ATTACH LOCALSTORAGE DATABASE TacticalWorldDb;
USE TacticalWorldDb;
`);
/*
Şimdi tablomuzu ele alalım. Submarine isimli tablomuzda
id, name, displacement ve country alanları yer alıyor.
Id alanı için otomatik artan bir primary key'de kullandık.
Örneği abartmamak adına alan dozajını belli bir seviyede tuttuk.
*/
alasql(`
CREATE TABLE IF NOT EXISTS Submarine (
id INT AUTOINCREMENT PRIMARY KEY,
name VARCHAR(25) NOT NULL,
displacement NUMBER NOT NULL,
country VARCHAR(25) NOT NULL
);
`);
}
/*
İlk satırda yer alan alasql komutu ile Submarine tablosundaki verileri displacement değerine
göre büyükten küçüğe sıralı olacak şekilde çekiyoruz.
Ardından state içeriğini bu tablo verisiyle ilişkilendiriyoruz.
*/
getAll() {
const submarineTable = alasql('SELECT * FROM Submarine ORDER BY displacement DESC');
this.setState({ skippers: submarineTable });
// console.log(submarineTable); // Kontrol amaçlı açıp F12 ile geçilecek kısımda Console sekmesinden takip edebiliriz. Bir JSON array olmasını bekliyoruz
}
/*
Bileşen DOM nesnesine bağlandıktan sonra çalışan metodumuzdur.
Burası örneğin tablo içeriğini çekip state nesnesine almak için
son derece ideal bir yerdir.
*/
componentDidMount() {
this.getAll();
}
/*
Yeni bir satır eklemek için aşağıdaki metodu kullanacağız.
denizaltının adı, tonajı ve menşei gibi bilgileri
this.refs özelliği üzerinden yakalyabiliriz. this.refs DOM
elemanlarına erişmek için kullanılmakta. Bu şekilde
formdaki input kontrollerini yakalayıp value niteliklerini
okuyarak gerekli veriyi çekebiliriz
Insert sorgusu için yine alasaql nesnesinden yararlanıyoruz.
Bu sefer parametre içeriğini tek ? içerisinde yollamaktayız.
Parametre değerleri aslında bir json nesnesi içinden yollanıyor.
key olarak kolon adını, value olarak da refs üzerinden gelen bileşene ait value özelliğini veriyoruz.
Id alanının otomatik arttırmak içinse autoval fonksiyonu devreye girmekte.
Pek tabii yeni eklenen kayıt nedeniyle bileşeni güncellemek lazım.
getAll metodu burada devreye girmekte
*/
addSkipper() {
const { name, displacement, country } = this.refs;
if (!name.value) return;
// console.log(dicplacement.value); // Kontrol amaçlı. Browser'dan F12 ile değerlere bakılabilir
alasql('INSERT INTO Submarine VALUES ?',
[{
id: alasql.autoval('Submarine', 'id', true),
name: name.value,
displacement: displacement.value,
country: country.value
}]
);
this.getAll();
}
/*
Silme operasyonunu yapan metodumuz.
Parametre olarak gelen id değerine göre bir DELETE ifadesi çağırılı
ve tüm liste tekrardan çekilir.
*/
deleteSkipper(id) {
alasql('DELETE FROM Submarine WHERE id = ?', id);
this.getAll();
}
/*
State değişikliği gibi durumlarda bileşen güncellenmiş demektir.
Bu durumda render fonkisyonu devreye girer.
render metodu bir HTML içeriği döndürmektedir.
form sınıfındaki input kontrollerinin ref niteliklerine dikkat edelim.
Bunları addSkipper metodunda this.refs ile alıyoruz.
iki button bileşenimiz var ve her ikisinin onClick metodları ilgili fonksiyonları
işaret ediyor.
HTML sayfası iki kısımdan oluşuyor. Yeni bir veri girişi yaptığımız form ve tablo verisini
gösteren bölüm. Tablo içeriğini birer satır olarak ekrana basmak için map fonksiyonundan
yararlanıyoruz. map fonksiyonu lambda görünümlü blok içerisine sırası gelen satır bilgisini
atıyor. Örnekte ship isimli değişken bu taşıyıcı rolünü üstlenmekte. ship değişkeni üzerinden
tablo kolon adlarını kullanarak asıl verilere ulaşıyoruz.
*/
render() {
const { skippers } = this.state;
return (
<main className="container">
<h2 className="mt-4">En Büyük Denizlatılar</h2>
<div className="row mt-4">
<form>
<div className="form-group mx-sm-3 mb-2">
<input type="text" ref="name" className="form-control" id="inputName" placeholder="Sınıfı" />
</div>
<div className="form-group mx-sm-3 mb-2">
<input type="text" ref="displacement" className="form-control" id="inputDisplacement" placeholder="Tonajı" />
</div>
<div className="form-group mx-sm-3 mb-2">
<input type="text" ref="country" className="form-control" id="inputCountry" placeholder="Sahibi..." />
</div>
<div className="form-group mx-sm-3 mb-2">
<button type="button" className="bnt btn-primary mb-2" onClick={e => this.addSkipper()}>Ekle</button>
</div>
</form>
</div>
<div>
<table className="table table-primary table-striped">
<thead>
<tr>
<th scope="col">Sınıfı</th>
<th scope="col">Tonajı</th>
<th scope="col">Ülkesi</th>
<th></th>
</tr>
</thead>
<tbody>
{
skippers.length === 0 && <tr>
<td colSpan="5">Henüz veri yok</td>
</tr>
}
{
skippers.length > 0 && skippers.map(ship => (
<tr>
<td>{ship.name}</td>
<td>{ship.displacement}</td>
<td>{ship.country}</td>
<td>
<button className="btn btn-danger" onClick={e => this.deleteSkipper(ship.id)}>Sil</button>
</td>
</tr>
))
}
</tbody>
</table>
</div>
</main >
);
}
}
export default App;</pre>
<p>Aslında CRUD<em>(Create Read <span style="text-decoration: line-through;">Update</span> Delete)</em> operasyonlarını sunmaya çalıştığımız bir arayüz var. Senaryomuzda dünyanın en büyük denizaltılarını listelediğimiz, ekleyip çıkarttığımız bir web bileşeni söz konusu. Tahmin edeceğiniz üzere benim hep atladığım bir şey daha var...Güncelleme eksik :| Artık o kısmını da siz değerli okurlarıma bırakıyorum.</p>
<p>Öyleyse aşağıdaki terminal komutunu vererek uygulamamızı çalıştıralım <em>(Bu arada react uygulamasını şablondan oluşturduğumuz için package.json içerisindeki scripts kısmı otomatik olarak ayarlanmıştır. start anahtar kelimesini kullanmamızın sebebi bu)</em></p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">npm run start</pre>
<p>İşte çalışma zamanına ait bir kaç görüntüsü.</p>
<p>Her şey yeni başlarken ve hiç veri yokken ana sayfa aşağıdaki gibi açılmalıdır.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2019/09/25/credit_2.png" alt="" /></p>
<p>Bir kaç satır ekledikten sonraki durum ise şöyle olacaktır.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2019/09/25/credit_3.png" alt="" /></p>
<h2>Local Storage Nerede?</h2>
<p>Peki veriyi tarayıcımız nerede tutuyor? Sonuçta In-Memory bir veritabanı olduğundan bahsediyoruz. Lakin içerik tarayıcı tarafında bir alanda konumlanıyor. Varsayılan senaryoda veri Local Storage bölümünde depolanmakta. Uygulamayı çalıştırdıktan sonra Chrome DevTools'a geçip Application sekmesine giderek içeriğini görebiliriz. Dikkat edileceği üzere TacticalWorldDb.Submarine isimli bir tablo bulunuyor ve verilerimiz içerisinde JSON nesneler olarak tutuluyor <em>(Diğer yandan depolama alanı olarak componentWillAmount metodu içerisindeki SQL komutumuzda LocalStorage'ı ifade ettiğimizi hatırlayalım)</em></p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2019/09/25/credit_5.png" alt="" /></p>
<p>Storage sekmesine bakarsak Local Storage dışında IndexedDB seçeneği de bulunmaktadır. Eğer bu alanı kullanmak istersek</p>
<pre class="brush:sql;auto-links:false;toolbar:false" contenteditable="false">ATTACH INDEXEDDB DATABASE TacticalWorldDB</pre>
<p>gibi bir SQL ifadesinden yararlanmamız gerekiyor. Tabii bu arada önemli bir soru da gündeme geliyor. Uygulamayı kapattığımızda veriye ne olacak? Bunu cevaplayabilmeniz için kodu buraya kadar geliştirmiş olmanız gerekiyor :)</p>
<h2>Ben Neler Öğrendim?</h2>
<p>Bazen sıfırdan başlanacak bir ürün için ya da lisans maliyetleri ve diğer sebepler nedeniyle modernize edilecek bir proje için verinin nerede neyle tutulacağını araştırmak isteyebiliriz. Böyle durumlarda alternatifleri POC<em>(Proof of Concept)</em> tadındaki deneysel programlarda denemek faydalıdır. Bende buna istinaden AlaSQL'i incelemiştim. Yanıma kar olarak kalanlarsa şöyle.</p>
<ul>
<li>Hazır bir react uygulama iskeletinin nasıl oluşturulduğunu</li>
<li>React sayfası içerisindeki yaşam döngüsüne dahil olan componentWillMount, componentDidMount ve render metodlarının hangi aşamalarda devreye girdiğini</li>
<li>Alasql paketinin react uygulamasına nasıl dahil edildiğini ve temel SQL ifadelerini<em>(veritabanı nesnelerini oluşturmak, insert ve delete sorgularını çalıştırmak vb)</em></li>
<li>state özelliğini ne amaçla kullanabileceğimi</li>
<li>Veritabanından çekilen JSON dizisinin map fonksiyonu ile nasıl etkileştiğini</li>
<li>refs özelliği ile kontrollerin metotlarda nasıl ele alınabildiğini</li>
</ul>
<p>Böylece geldik bir <a href="https://github.com/buraksenyurt/saturday-night-works" target="_blank">saturday-night-works</a> notu derlemesinin daha sonuna. Yolun açık olsun Skipper :) Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>2019-11-11T10:30:00+00:00reactalasqljavascriptsqldatabasenodenode.jsjavascriptDatabasejsonnosqlindexedDbcrudnpmnpxcreate-react-appbsenyurtÖğrenecek bir şeyler araştırırken AlaSQL isimli bir çalışma ile karşılaştım. Tarayıcı üzerinde çalışabilen istemci taraflı bir In-Memory veritabanı olarak geçiyor. Tamamen saf Javascript ile yazılmış. Geleneksel ilişkisel veritabanı özelliklerinin çoğunu barındırıyor. Group, join, union gibi fonksiyonellikleri karşılıyor. In-Memory tutulan veriyi kalıcı olarak saklamakta mümkün. Hatta bu noktada localStorage olarak ifade edilen yerel depolama'dan veri okunup tekrar yazılabiliyor. IndexedDB veya Excel'ide fiziki repository olarak kullanabiliyor. Ayrıca JSON nesnelerle çalışabiliyoruz ki bu da NoSQL desteği anlamına gelmekte. Benim amacım onu yalın bir React uygulamasında deneyimlemeye çalışmak.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=23d3c02e-8ebf-4d94-a268-f818103ce96c4https://buraksenyurt.com/trackback.axd?id=23d3c02e-8ebf-4d94-a268-f818103ce96chttps://buraksenyurt.com/post/bir-react-uygulamasinda-en-ala-sql-veritabanini-kullanmak#commenthttps://buraksenyurt.com/syndication.axd?post=23d3c02e-8ebf-4d94-a268-f818103ce96chttps://buraksenyurt.com/post/bu-sefer-bir-react-uygulamasini-heroku-uzerine-alalimBu Sefer Bir React Uygulamasını Heroku Üzerine Alalım2019-10-04T13:00:00+00:00bsenyurt<p><img style="float: right;" src="https://buraksenyurt.com/image.axd?picture=/2019/06/08/hamlett.png" alt="" />Sir <a href="http://sirkenrobinson.com/" target="_blank">Ken Robinson</a>, çocukların hayal güçlerini sınırlayan eğitim sistemini eleştirdiği <a href="https://www.ted.com/talks/ken_robinson_says_schools_kill_creativity?language=en" target="_blank">TED'in en çok izlenen sunumu</a>nda William Shakespeare ile ilgili güzel bir anektod paylaşır. Konuşmasının ilgili bölümünde profesör onun bir zamanlar yedi yaşında bir çocuk olduğunu dile getirir. Kısa bir an için duraksar ve ne diyeceğini merak eden seyirciye "...Shakespeare'i hiç çocuk olarak düşünmemiştiniz, değil mi?" der :)</p>
<p>Hepimiz onu ünlü İngiliz şair ve yazar olarak bilir Romeo Juliet, Macbeth, Othello ve diğer trajedileri ile hatırlarız. Hatta "olmak yada olmamak, işte bütün mesele bu" sözleri hafızalarımıza kazınmıştır. Ancak çoğumuz onun da bir zamanlar çocuk olduğunu ve bir öğretmenin edebiyat dersine girdiğini düşünmeyiz<em>(Bunu Ken Robinson gayet güzel bir şekilde düşündürtüyor)</em> Onun da hepimiz gibi çocukken kurduğu hayaller olduğunu bu cümleleri duyana kadar da fark etmeyiz. Çok şükür ki <a href="https://github.com/buraksenyurt/saturday-night-works/tree/master/No%2008%20-%20Express%20with%20React%20to%20Heroku" target="_blank">sekiz numaralı çalışma</a>mın içerisinde geçen bir kelime benim onu, onun yardımıyla Sir Ken Robinson'u ve sonrasında da bu güzel anekdotu hatırlamamı sağladı. Nihayetinde Shakespeare'in ölümsüz eserlerinden olan Hamlet'in Heroku tarafından bana önerilmesi işte bu kısa girizgahın hayat bulmasına vesile oldu. </p>
<p>Sekiz numaralı örnekteki amacım node.js ile çalıştırılan basit bir React uygulamasını Heroku üzerine taşımaktı. React ile node haberleşmesinde express paketini kullanmıştım. Bu paket deneyimlediğim kadarıyla HTTP yönlendiricisi olarak kullanılmaktaydı. React tarafına gelen HTTP taleplerini karşılarken kullanılabilmekte. Diğer yandan React tarafında çok fazla tecrübem olmadığından benim için hala kapalı kutu olma özelliğini taşıyor. Bir nevi ona da merhaba demek istediğim bir çalışma olduğunu ifade edebilirim.</p>
<p><a href="https://www.heroku.com/" target="_blank">Heroku</a> 2007 yılında işe başladığında sadece Ruby on Rails bazlı web uygulamalarına destek veren bir bulut bilişim sistemiydi ancak Platform as a Service<em>(PaaS)</em> olarak olgunlaştıktan sonra Java, Node.js, Scala, Python, Go, Closure ve benzeri bir çok dil ile geliştirilen uygulmalar için de hizmet vermeye başladı. Aslında heroku üzerindeki ilk denememi 2018 yılında yapmış ve <a href="https://buraksenyurt.com/post/express-api-hizmetini-heroku-uzerine-tasimak" target="_blank">şöyle bir yazı</a> yazmıştım. Teknolojinin gelişimi düşünüldüğünde aradan yadsınamayacak kadar çok zaman geçmiş diyebilirim. O yüzden bu tip platformlara ara ara dönüş yaparak farklı enstrümanlarla kullanmayı denemek güncel kalmamız açısından önemli. Öyleyse vakit kaybetmeden <a href="https://github.com/buraksenyurt/saturday-night-works/tree/master/No%2008%20-%20Express%20with%20React%20to%20Heroku" target="_blank">sekiz numaralı Cumartesi gecesi çalışması</a>nı derlemeye başlayalım.</p>
<h2>Gerekli Hazırlıklar</h2>
<p>Tabii öncelikle Heroku üzerinde bir hesap açmak gerekiyor. Ben gerekli hesabı açtıktan sonra WestWorld<em>(Ubuntu 18.04, 64bit) </em>üzerinde Heroku CLI<em>(command-line interface)</em> kurulumunu da yaptım. Böylece heroku ile ilgili işlemlerimizi terminal komutlarını kullanarak kolayca gerçekleştirebiliriz.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">sudo snap install --classic heroku</pre>
<p>Kurulum sonrası login olmamız gerekecektir.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">heroku login -i</pre>
<p>Yukarıdaki terminal komutunu çalıştırdıktan sonra credential bilgileri sorulur<em>(-i parametresini heroku login bilgilerinin kalıcı olması için kullanabiliriz) </em>Heroku tarafı ile iletişimi kurduğumuza göre uygulamanın çatısını oluşturmaya başlayabiliriz.<em> </em>Öncelikle app isimli bir klasör açıp aşağıdaki terminal komutu ile node tarafını başlatalım. Biraz sonra kuracağımız React uygulamamız ile konuşacağı basit node sunucusu bu klasörde yer alacak.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">npm init</pre>
<p>Bazı yardımcı paketlerimiz var. Bunları şu terminal komutu ile yükleyebiliriz.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">npm i --save-dev express nodemon concurrently</pre>
<p>express, servis tarafını daha kolay kullanabilmemiz için gerekli özellikleri sunan bir paket. nodemon ile de node.js tarafında yapılan değişikliklerin otomatik olarak algılanması sağlanıyor. Yani uygulamayı tekrar başlatmaya gerek kalmadan kod tarafındaki değişikliklerin çalışma zamanına yansıtılması sağlanabilir. concurrently paketi hem express hem react uygulamalarının aynı anda başlatılması için kullanılmakta. Paket yüklemeleri tamamlandıktan sonra app kök klasörü altında server.js isimli bir dosya oluşturup kodlamasını sonradan tamamlamak üzere çalışmamıza devam edebiliriz.</p>
<h2>React Uygulamasının Oluşturulması</h2>
<p>React uygulmasını standart bir hello-world şablonu şeklinde açacağız. Bunun için aşağıdaki terminal komutunu kullanmamız yeterli.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">npm i -g create-react-app
create-react-app fromwestworld</pre>
<blockquote>
<p>Bu arada create-react-app komutu ile uygulamayı oluştururken şunu fark ettim ki proje adında sadece küçük harf kullanılabiliyor. İlerde değişir mi, siz bunu okurken değişmiş midir, neden böyledir tam bilemiyorum ama bir unix isimlendirme standardından kaynaklıdır diye düşünüyorum<em>(Fikri olan?)</em></p>
</blockquote>
<p>Bir süre geçtikten sonra fromwestworld klasörü içerisinde React için gerekli ne varsa oluşturulduğunu görürüz. Oluşturulan bu şablonu çok fazla bozmadan kullanabiliriz. </p>
<p>Şimdi geliştirme ortamı için fromwestworld klasöründeki package.json içerisine bir proxy tanımı ekleyerek devam edelim. Biraz sonra kodlayacağımız node sunucumuz 5005 numaralı porttan yayın yapacak<em>(geliştirme ortamı için farklı bir portta tercih edilebilir)</em> Bu bildirim ile React uygulmasının geliştirme ortamında konuşacağı servis adresi ifade edilir. Bir başka deyişle React'a gelen HTTP taleplerinin yönlendirileceği adresi belirtiyoruz.</p>
<pre class="brush:js;auto-links:false;toolbar:false" contenteditable="false">"proxy": "http://localhost:5005",</pre>
<p>Şablonla gelen app.js içeriğini aşağıdaki gibi değiştirebiliriz. İçeriğin şu anda çok fazla önemi yok. Hedefimiz olan Heroku deployment için mümkün mertebe basit kodlar kullanmakta yarar var.</p>
<pre class="brush:js;auto-links:false;toolbar:false" contenteditable="false">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" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://www.buraksenyurt.com"
target="_blank"
rel="noopener noreferrer"
>
Bu benim blog sayfamdır :)
</a>
</header>
</div>
);
}
}
export default App;</pre>
<p>React uygulamasının iletişimde olacağı sunucuya ait server.js dosyasını da aşağıdaki gibi yazabiliriz. </p>
<pre class="brush:js;auto-links:false;toolbar:false" contenteditable="false">var express = require('express');
var app = express();
var path = require('path');
var port = process.env.PORT || 5005; //heroku'nun portu veya local geliştirme için belirlediğimiz 5005 nolu port
// statik klasör bildirimini yapıyoruz
app.use(express.static(path.join(__dirname, 'fromwestworld/build')));
//canlı ortamdaysak yani uygulamamız Heroku'ya alınmışsa
if (process.env.NODE_ENV === 'production') {
// build klasöründen index.html dosyasını alıp get talebinin karşılığı olarak istemciye sunuyoruz
app.use(express.static(path.join(__dirname, 'fromwestworld/build')));
app.get('*', (req, res) => {
res.sendfile(path.join(__dirname = 'fromwestworld/build/index.html'));
})
}
// Eğer canlı ortamda(heroku'da) değilsek ve amacımız sadece localhost'ta test ise
// index.html'i public klasöründen sunuyoruz
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname + '/fromwestworld/public/index.html'));
})
// express sunucusunu çalıştırıyoruz
app.listen(port, (req, res) => {
console.log(`sunucumuz ${port} nolu porttan yayındadır`);
})</pre>
<p>Temel olarak bulunulan ortama<em>(development veya production)</em> göre public klasöründe yer alan<em>(ve benim üzerinde hiçbir değişiklik yapmadığım)</em> index.html sayfasının sunulması söz konusu. Kod tarafındaki bu değişiklilere ilaveten root klasör olarak düşüneceğimiz app altındaki package.json dosyasındaki scripts kısmını da kurcalamalıyız. Güncel hali aşağıdaki gibi.</p>
<pre class="brush:js;auto-links:false;toolbar:false" contenteditable="false">"scripts": {
"client-install": "npm install --prefix fromwestworld",
"start": "node index.js",
"server": "nodemon index.js",
"client": "npm start --prefix fromwestworld",
"dev": "concurrently \"npm run server\" \"npm run fromwestworld\""
}</pre>
<p>Bunlardan start haricindekiler <em>npm run</em> arkasına eklenen komutlardır. Örneğin <em>npm start</em> ile <em>node index.js</em> komutu ve dolayısıyla uygulama çalışır. Diğer yandan <em>npm run server</em> ile nodemon devreye alınır ve kodda yapılan değişiklik anında çalışma zamanına yansır. <em>npm run client,</em> sunucuyu başlatmadan react uygulamasını çalıştırma görevini üstlenir. <em>npm run client-install</em> sayesinde ise React uygulaması için gerekli tüm bağımlılıklar ilgili ortama<em>(örnekte Heroku olacaktır)</em> yüklenir. <em>npm run dev</em> ile development ortamı ayağa kalkar ve hem node sunucusu hem de react uygulaması aynı anda başlatılır.</p>
<p>Uygulamayı komple çalıştırmak için app klasöründeyken</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">npm run dev</pre>
<p>terminal komutunu işletebiliriz. concurrently paketi bu noktada bize avantaj sağlamaktadır. Eş zamanlı olarak "npm run server" ve "npm run client" komutlarının işletilmesinde rol alır.</p>
<p>Bu işlem sonrasında önce node sunucusu yüklenir. Sunucu çalışmaya başladıktan sonra React uygulaması tetiklenir ve localhost:3000 nolu porttan ilgili içeriğe ulaşılır. Hatırlayacağınız üzere node sunucusu 5005 numaralı porttan hizmet veriyordu. React uygulamasında yapılan proxy bildirimi, 3000 nolu adrese gelen HTTP taleplerinin arkadaki node sunucusuna yönlendirilmesinde rol alır. Dolayısıyla React uygulaması çalışmaya başladığında oluşan HTTP Get talebi server.js dosyasındaki get metodlarına düşer. Buradaki bildirimlere göre fromwestworld içerisindeki index.html dosyasının sunulması söz konusudur. index.html içeriğinde dikkat edileceği üzere root id'li bir div elementi vardır. Yine dikkat edilecek olursa index.js tarafı da aşağıdaki gibidir <em>(Hiç değiştirmedim)</em></p>
<pre class="brush:js;auto-links:false;toolbar:false" contenteditable="false">import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();</pre>
<p>ReactDOM.render metoduna dikkat edelim. root isimli DOM elementini yakalayıp buraya app isimli bileşenin basılması sağlanmaktadır. Özetlemek gerekirse React uygulaması kendi içeriklerini sunarken arka plandaki node sunucusu ile anlaşmaktadır. Buna göre server.js tarafında sunucu bazlı materyalleri<em>(veri tabanı, asenkron operasyonlar vb)</em> kullanarak bunların react bileşenlerince ele alınması sağlanabilir.</p>
<p>Çalışmayı gerçekleştiğimde West-World tarafında uygulamanın açılması biraz zaman almıştı. Sizin de benim gibi sebat edip panik yapmadan beklemeniz gerekebilir. İşte çalışma zamanı görüntüleri.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2019/06/08/credit_1.png" alt="" /></p>
<p>Her şey yolunda giderse localhost:3000 adresinden aşağıdaki içeriğe ulaşabiliriz.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2019/06/08/credit_2.png" alt="" /></p>
<h2>Uygulamanın Heroku Platformuna Alınması</h2>
<p>Öncelikle Heroku üzerinde bir uygulama oluşturmamız gerekiyor. Bunu aşağıdaki terminal komutuyla yapabiliriz.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">heroku create</pre>
<p>Bana proje adı olarak Heroku'nun otomatik olarak ürettiği <em>frozen-hamlet-75426</em> denk geldi. Ayrıca uygulama kodlarını atabilmek için github ve ulaşacağım web adresi bilgisi de iletildi.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2019/06/08/credit_3.png" alt="" /></p>
<p>Uygulamanın web adresi https://frozen-hamlet-75426.herokuapp.com/ şeklinde. github adresi ise https://git.heroku.com/frozen-hamlet-75426.git. Hatta sonuçları Heroku Dashboard üzerinden de görebiliriz<em>(Tabii siz örneği denerken güncel hali Heroku üzerinde olmayabilir. Kendiniz için bir tane yapsanız daha iyi olur)</em></p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2019/06/08/credit_4.png" alt="" /></p>
<p>Uygulama klasöründeki json dosyasında yer alan heroku-postbuild script'i bu aşamada önem kazanıyor. Kodlar git ortamına taşındıktan sonra bir build işlemi gerekiyor. Heroku bu script kısmını ele alıyor.</p>
<pre class="brush:plain;auto-links:false;toolbar:false" contenteditable="false">"heroku-postbuild":"NPM_CONFIG_PRODUCTION=false npm install --prefix fromwestworld && npm run build --prefix fromwestworld"</pre>
<p>Bu düzenlemenin ardından yazılan kodların geliştirme ortamından github üzerine atılması gerekiyor. Yani Heroku'nun kod deposu olarak github'ı kullandığını ifade edebiliriz. Aşağıdaki komutlarla devam edelim öyleyse.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">heroku git:remote -a frozen-hamlet-75426
git add .
git commit -am 'Heroku React Express örneği eklendi'
git push heroku master</pre>
<p>Yapılanları aşağıdaki gibi özetleyebiliriz.</p>
<ol>
<li>Heroku için git remote adresini belirle</li>
<li>Tüm değişiklikleri stage'e al</li>
<li>Değişiklikleri onayla<em>(commit)</em></li>
<li>ve kodun son halini master branch'e push'la</li>
</ol>
<p>Kodun github'a alınması aynı zamanda heroku'nun da ilgili uygulamayı gerekli build betiklerini çalıştırarak devreye alması anlamına gelmekte. Dolayısıyla bir süre sonra https://frozen-hamlet-75426.herokuapp.com/ adresine gitmek sonuçları görmemiz açısından yeterli olacaktır.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2019/06/08/credit_5.png" alt="" /></p>
<h2>Bazı Hatalarım da Olmadı Değil</h2>
<p>Çalışma sırasında bu basit hello-world uygulamasını tek seferde Heroku'ya taşıyamadığımı ifade etmek isterim. Eğer taşıma sırasında sorunlarla karşılaşırsanız bunları görmek için terminalden</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">heroku logs --tail</pre>
<p>komutunu kullanabilirsiniz. Yaşadığım sorunları ve çözümlerini aşağıdaki maddelerde bulabilirsiniz.</p>
<ul>
<li>İlk hatam server.js dosyasında process.env.PORT yerine process.env.port kullanmış olmamdı. Heroku ortamı bu port'u anlamadığı için 5005 nolu porttan yayın yapmaya çalıştı ki bu mümkün değildi.</li>
<li>İkinci hatam package.json içerisinde ortam için gerekli node engine versiyonunu söylememiş olmamdı. Nitekim Heroku tarafı node'un hangi sürümünü kullanacağını bilmek ister.</li>
<li>Diğer problemse bağımlı olunan npm paketleri için package.json dosyasında dependencies yerine devDependencies sektörünü bırakmış olmamdı. Üretim ortamı için dependencies kısmına bakılıyor.</li>
<li>Ayrıca .gitignore dosyasını koymayıp node_modules ve package-log.json öğelerini hariç tutmadığım için bu klasörleri de komple push'lamış oldum<em>(Sonraki versiyonda düzelttim tabii)</em></li>
</ul>
<p>Bu hususlara dikkat ettiğimiz takdirde ürünü başarılı bir şekilde yayına almış oluruz. Tabii uygulamanın şu an için yaptığı hiçbir şey yok. Oysa ki PostgreSQL kullanaraktan veri odaklı basit bir Hello World uygulaması pekala geliştirilebilir. Daha önceden sıkça dile getirdiğim üzere bu kutsal görevi siz değerli okurlarıma bırakıyorum :)</p>
<h2>Ben Neler Öğrendim?</h2>
<p>Uzun süre sonra derlemek üzere ele aldığım bu çalışmada Heroku üzerine bir React uygulamasının nasıl alındığını hatırlayıp bilgilerimi tazeleme fırsatı buldum. Kabaca yaptıklarımın üstünden geçtikten sonra öğrendiklerimi aşağıdaki maddeler halinde ifade edebileceğimi düşünüyorum.</p>
<ul>
<li>Heroku'da hesap açma ve uygulama oluşturma adımlarını</li>
<li>Heroku CLI üzerinden dağıtım işlemlerinin nasıl yapıldığını</li>
<li>Bir node sunucusu üzerinden bir React uygulamasının ayağa kaldırılmasını</li>
<li>En temel düzeyde app react bileşeninin nerede nasıl kullanıldığını</li>
<li>Deployment sırasında veya çalışma zamanındaki hatalara ait loglara nasıl bakıldığını</li>
</ul>
<p>Böylece geldik bir <a href="https://github.com/buraksenyurt/saturday-night-works" target="_blank">cumartesi gecesi derlemesi</a>nin daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>2019-10-04T13:00:00+00:00reactnodenode.jsherokupaasplatform as a servicecloud servicesdeploymentnpmexpressnodemonconcurrentlybsenyurtSekiz numaralı örnekteki amacım node.js ile çalıştırılan basit bir React uygulamasını Heroku üzerine taşımaktı. React ile node haberleşmesinde express paketini kullanmıştım. Bu paket deneyimlediğim kadarıyla HTTP yönlendiricisi olarak kullanılmaktaydı. React tarafına gelen HTTP taleplerini karşılarken kullanılabilmekte. Diğer yandan React tarafında çok fazla tecrübem olmadığından benim için hala kapalı kutu olma özelliğini taşıyor. Bir nevi ona da merhaba demek istediğim bir çalışma olduğunu ifade edebilirim.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=e51b55f0-4009-4895-9689-f8465cb068492https://buraksenyurt.com/trackback.axd?id=e51b55f0-4009-4895-9689-f8465cb06849https://buraksenyurt.com/post/bu-sefer-bir-react-uygulamasini-heroku-uzerine-alalim#commenthttps://buraksenyurt.com/syndication.axd?post=e51b55f0-4009-4895-9689-f8465cb06849