- Node ve npm kurulumu gereklidir.
npm install create-react-app
react projesini basit bir şekilde kurmaya yarayan paketin kurulumu
npx create-react-app project-name
az önce kurduğumuz paketi istediğiniz dosyaya terminal üzerinden giderek yukarıdaki komut ile projenizi oluşturabilirsiniz.
npm start
komutu ile ilk projenizi ayaklandırabilirsiniz.
Bu dosya projenin npm paketlerini yönetmek için kullanılan bir manifesto dosyasıdır. Bu dosyanın içersinide bulunan dependencies bölümünde javascript projemizde kullanılan kütüphaneler ve sürümleri bulunur. Scripts bölümünde ise terminalde çalışacak kısaltmaların açılımları bulunur.
Bu dosya hazır gelen projede public klasörünün içinde bulunur sitenin kendi html sayfasıdır içine girdiğinizde id değeri roota eşit olan bir div elementi görürsünüz react bu dive bağlıdır ve react ile oluşturacağınız bütün yapılar bu divin içinde render edilecektir.
Bu dosya hazır gelen projede src klasörünün içinde bulunur açıldığında göreceğiniz üzere render fonksiyonu yer alır ve yazılmış olan app.js i ekrandaki root id li elemente render eder.
Hazır gelen projede görsel parçaları return eden dosyadır.
jsx javascript dosyaları içerisine html syntax i ile elementler yazmayı sağlayan bir formattır. Tek html elementinden oluşmalıdır.
JSX formatı compile edilirken bütün html elementleri Reactin içinde bulunan createElement metotu ile react elementlerine dönüştürülür.
const h1 = <h1>Hello world</h1>;
Bu const ile
const h1 = React.createElement(
"h1",
null,
"Hello, world"
);
Bu const tamamen aynı şeydir fakat aşşağıdaki jsx kullanılmadan yazılmıştır.
html de yaygın olarak kullanılan attribute lerin çoğu burada farklı yazılmalıdır mesela
<div class="App"></div>
<div className="App"></div>
yukarıdaki gibi class yerine className kullanılmalıdır.
Jsx elementleri herhangi bir değişkenede atanabilir.
const myList = (
<ul>
<li>Love</li>
<li>LOVE</li>
<li>LOVE!!!</li>
</ul>
);
/////////////////////
const link = (
<a href="https://www.codecademy.com">
<h1>Codecademy</h1>
</a>
);
////////////////////////
const example = <h1 id="example">JSX Attributes</h1>;
//////////////////////
const goose = 'https://s3.amazonaws.com/codecademy-content/courses/React/react_photo-goose.jpg';
const gooseImg = <img src={goose}/>
JavaScript kütüphanesi olan ReactDom oluşturduğunuz JSX elementlerini DOM un anlayabileceği bir formatta DOM ağacında gösterdiğiniz yere ekler.
ReactDOM.render(
<h1>"This is an example.""</h1>,
document.getElementById('app')
);
Bu örnek JSX yaklaşımlarının ekranda gösterilmesidir. Ekranda: "This is an example." yazmalıdır.
function makeDoggy(e) {
e.target.setAttribute('src', 'https://s3.amazonaws.com/codecademy-content/courses/React/react_photo-puppy.jpeg');
e.target.setAttribute('alt', 'doggy');
}
const kitty = (
<img
src="https://s3.amazonaws.com/codecademy-content/courses/React/react_photo-kitty.jpg"
alt="kitty"
onClick={makeDoggy}/>
);
ReactDOM.render(kitty, document.getElementById('app'));
Yukarıda bulunan örnek ekrana render edilen resimin üzerine tıklanınca değişmesini sağlar onClick eventleri bu şekilde atayabilirsiniz.
Çalışmayan if yazımı
<h1>
{
if (purchase.complete) {
'Thank you for placing an order!'
}
}
</h1>
Yukarıda bulunan kod çalışmayacaktır. if leri bu şekilde süslü parantezlerle jsx in içine yazamazsınız.
Çalışan if yazımı
import React from 'react';
import ReactDOM from 'react-dom';
function coinToss() {
// This function will randomly return either 'heads' or 'tails'.
return Math.random() < 0.5 ? 'heads' : 'tails';
}
const pics = {
kitty: 'https://s3.amazonaws.com/codecademy-content/courses/React/react_photo-kitty.jpg',
doggy: 'https://s3.amazonaws.com/codecademy-content/courses/React/react_photo-puppy.jpeg'
};
let img;
// if/else statement begins here:
if (coinToss() === "heads"){
img = (
<img src= {pics.kitty} />
);
}else{
img = (
<img src= {pics.doggy} />
);
}
ReactDOM.render( img , document.getElementById('app'))
Yukarıdaki örnekte çalışan bir if bloğu yazılmıştır atılan yazı turanın sonucuna göre kedi yada köpek fotoğrafı render eden bir programdır.
const img = <img src={pics[coinToss() === 'heads' ? 'kitty' : 'doggy' ]} />;
ReactDOM.render(
img,
document.getElementById('app')
);
Ya da ternary operator kullanarak bu şekilde de yazılabilir.
JSX in içinde if kullanamayız ama ifin içerisinde JSX döndürebiliriz.
&& operatörü bir durum sağlanıyorsa bir şeyler yapar sağlanmıyorsa hiçbir şey yapmamak üzerine çalışır.
import React from 'react';
import ReactDOM from 'react-dom';
// judgmental will be true half the time.
const judgmental = Math.random() < 0.5;
const favoriteFoods = (
<div>
<h1>My Favorite Foods</h1>
<ul>
<li>Sushi Burrito</li>
<li>Rhubarb Pie</li>
{ !judgmental && <li>Nacho Cheez Straight Out The Jar</li>}
<li>Broiled Grapefruit</li>
</ul>
</div>
);
ReactDOM.render(
favoriteFoods,
document.getElementById('app')
);
Yukarıdaki örnekte %50 şans ile listedeki "Nacho Cheez Straight Out The Jar" elementi ekranda belirecektir.
Bir array methodu olan .map i JSX in içindede rahatça kullanılabiliyor.
const strings = ['Home', 'Shop', 'About Me'];
const listItems = strings.map(string => <li>{string}</li>);
<ul>{listItems}</ul>
Bu örnekte ise hazırda bulunan strings arrayini dolaşıp içinde bulunan bütün elemanları li tagleri ile sarar ve ul tagleri arasında JSX elemntlerine dönüşmüş olan arrayi ul içine atarak bir liste oluşturulmakta.
const liArray = [
<li>item 1</li>,
<li>item 2<li>,
<li>item 3</li>
];
// yukarıdaki örnek ile tamamen aynı sadece .map kullanmadan da yapılabilir.
<ul>{liArray}</ul>
.map() fonksiyonu ile her liste elemanına farklı bir key value verebiliriz mesela ;
const people = ['Rowe', 'Prevost', 'Gare'];
const peopleLis = people.map((person , i) =><li key={'person_' + i}>{person}</li>);
Bir for döngüsü gibi davranacak olan .map in içine bir de girdi olarak i değeri verip bunuda li lerin içine key attribute olarak ekleyebiliriz
React kullanılan uygulamalar componentler dan oluşur. Componentlar küçük, yeniden kullanılabilir ve tek bir amacı olan kod parçalarıdır. Bu iş genelde bir parça HTML render etmektir
import React from 'react';
import ReactDOM from 'react-dom';
class MyComponentClass extends React.Component {
render() {
return <h1>Hello world</h1>;
}
};
ReactDOM.render(
<MyComponentClass />,
document.getElementById('app')
);
Yukarıdaki örnekte basit bir hello world component'ı oluşturulmuştur.
import React from 'react';
Bütün react kodlarının başına yazılan bu satır React adında bir değişken yaratır ve bu değişkenin değerini ise import edilmiş bir JavaScript objesidir.,
İmport edilen bu obje React'i kullanabilmeniz için gerekli methodları (React.getElement() gibi) içinde barındırır.
Bir önceki bölümde anlattığım gibi JSX yaklaşımını kullandığımızda bu HTMLvari kodlar bu reactin getElement metotuna göre compile edilir en basitinden bu yüzden bile reacti import etmeniz gerekir
import ReactDOM from 'react-dom';
Bu ikinci satır ilkine çok benzer olup aynı işi yapar fakat aralarındaki fark bu sefer reactin DOM la ilgili ReactDOM.render() gibi metotların bulunduğu kütüphaneyi çağırmayı sağlar.
Bu işlem OOP (Object Oriented Programming) bilgisi gerektirmektedir.
Componentlar küçük, yeniden kullanılabilir ve tek bir amacı olan kod parçaları olduklarından yukarıda bahsetmiştim componentlar aynı zamanda React kütüphanesinde bulunan Component base classından türemek zorundadır.
Bir component yapmak için React kütüphanesindeki React.Component base classını şu şekilde kullanırız.
class MyComponentClass extends React.Component {
render() {
return <h1>Hello world</h1>;
}
}
Component a bir isim vermeniz gerekir ismini MyComponentClass yerine istediğinizi yazabilirsiniz ama component isimleri büyük harfle başlamalıdır. Componentların içinde bir render methodu kullanılmalıdır ve amacına uygun JSX kod parçasını return etmelidir. Bu örnekte componentimiz "Hello world" h1 başlığını return etmektedir. Peki bu componenti nasıl tekrar çağıracağız.
ReactDOM.render(
<MyComponentClass />,
document.getElementById('app')
);
JSX elementleri HTMLvari ya da component olarak yazılabilir.JSX bu ikisinin farkını baş harflerinin büyük olup olmamasından ayırır bu da component isimlerini neden büyük harfle başladığımızın nedenidir. Büyük harf ile başlayan tagler JSX'e "ben HTML kodu yerine bir react componentiyim" der.
Yukarıdaki örnekte componentimiz h1 başlığını render ederken kullandığımız ReactDOM.render methodu bu componentin render ettiği JSX i ekrana yazdırır.
import React from 'react';
import ReactDOM from 'react-dom';
class QuoteMaker extends React.Component {
render() {
return (
<blockquote>
<p>
The world is full of objects, more or less interesting; I do not wish to add any more.
</p>
<cite>
<a target="_blank"
href="https://en.wikipedia.org/wiki/Douglas_Huebler">
Douglas Huebler
</a>
</cite>
</blockquote>
);
}
};
ReactDOM.render(
<QuoteMaker />,
document.getElementById('app')
);
Yukarıdaki örnekte render metotunda döndürülen JSX in parantezler içerisinde olduğunu farkettiniz mi şimdiye kadar yaptığımız örneklerde hep tek satır JSX döndüğümüz için parantez kullanmamıştık fakat çok satırlı JSX bloklarının hepsi parantezler içerisinde yazılmalıdır. Bu yüzden yukarıdaki örnekte JSX bloğu parantez içerisine yazılmıştır.
import React from 'react';
import ReactDOM from 'react-dom';
const redPanda = {
src: 'https://upload.wikimedia.org/wikipedia/commons/b/b2/Endangered_Red_Panda.jpg',
alt: 'Red Panda',
width: '200px'
};
class RedPanda extends React.Component {
render() {
return (
<div>
<h1>Cute Red Panda</h1>
<img
src={redPanda.src}
alt={redPanda.alt}
width={redPanda.width} />
</div>
);
}
}
ReactDOM.render(
<RedPanda />,
document.getElementById('app')
);
Yukarıdaki örnekte görüldüğü gibi redPanda classı oluşturulmuş ve özellikleri Component içerisinde döndürülen JSX formatının içinde attribute olarak kullanılmıştır.
import React from 'react';
import ReactDOM from 'react-dom';
const friends = [
{
title: "Yummmmmmm",
src: "https://s3.amazonaws.com/codecademy-content/courses/React/react_photo-monkeyweirdo.jpg"
},
{
title: "Hey Guys! Wait Up!",
src: "https://s3.amazonaws.com/codecademy-content/courses/React/react_photo-earnestfrog.jpg"
},
{
title: "Yikes",
src: "https://s3.amazonaws.com/codecademy-content/courses/React/react_photo-alpaca.jpg"
}
];
// New component class starts here:
class Friend extends React.Component {
render() {
let friend = friends[2];
return (
<div>
<h1>{friend.title}</h1>
<img src={friend.src} />
</div>
);
}
}
ReactDOM.render(<Friend />, document.getElementById('app'));
Yukarıdaki örnekte işin içine biraz mantık kattık ve ekrana gösterilecek değerin içeriğini direkt hazır arrayimizden istediğimiz classın özelliklerini kullanarak render ettik bu örnekte üçüncü eleman render edilecek.
import React from 'react';
import ReactDOM from 'react-dom';
const fiftyFifty = Math.random() < 0.5;
// New component class starts here:
class TonightsPlan extends React.Component{
render(){
let task;
if (!fiftyFifty) {
task = "I'm going to bed WOOO"
} else {
task = "Tonight I'm going out WOOO"
}
return <h1>{task}</h1>;
}
}
ReactDOM.render(
<TonightsPlan />,
document.getElementById('app')
);
Yukarıdaki örnekte if else in nasıl kullanıldığını görüyoruz bu tarz işlemlerin hepsi render metotunun içinde return önce yazılır. Bu örnekte fiftyFifty değişkeni her refreshte random bir şekilde true ya da false döndürecek ve kodumuzda bu random boolean a göre iki farklı planımız var onları ekrana yazdıracak.
class IceCreamGuy extends React.Component {
get food() {
return 'ice cream';
}
render() {
return <h1>I like {this.food}.</h1>;
}
}
Yukarıdaki örnekte this'in kullanımının basit bir örneği mevcut. this yapısı react componentlerinde bolca kullanılan bir yapı ancak genelde bu şekilde kullanılıyor. "food bir method değil mi onu neden orada this.food() şeklinde parantezlerle çağırmadık" gibi bir soru gelmişti benim aklıma ancak oradaki food fonksiyonu bir get fonksiyonu olduğu için gerek yok.
import React from 'react';
import ReactDOM from 'react-dom';
class Button extends React.Component {
scream() {
alert('AAAAAAAAHHH!!!!!');
}
render() {
return <button onClick={this.scream}>AAAAAH!</button>;
}
}
ReactDOM.render(<Button />, document.getElementById('app'));
Yukarıdaki örnekte ekrandaki buttona basit bir onClick listener atadık ve bu eventi scream metotuna bağladık böylelikle buttona basıldığında scream metotu çalışacak ve bir alert kutusu çıkaracak.
Component iletişimi.
Bir react projesi bünyesinde yüzlerce component bulundurabilir. Bütün componentler küçük ve kendi çapında anlamsız olabilir fakat bir araya geldiklerinde kompleks bir bilgi ekosistemi oluştururlar.
React projeleri componentlardan oluşur ama reacti özel yapan componentlar değil onların birbiri ile iletişimidir.
class OMG extends React.Component {
render() {
return <h1>Whooaa!</h1>;
}
}
class Crazy extends React.Component {
render() {
return <OMG />;
}
}
.render() fonksiyonunun JSX formatı döndürdüğünü yukarıda öğrenmiştik peki bu örnekteki ikinci component de JSX yerine bir başka component dönmekte bu şekilde componentlar birbirini render edebilir.
Oluşturacağınız onlarca componentı aynı js dosyası yerine projeniz içerisinde components adında bir dosya oluşturup bunun içerisinde farklı js uzantılı dosyalarda yazmanız ve aynı işleri yapan parçaları olabildiğince küçük parçalara ayırmanız gerekmektedir. Ayıracağınız bu farklı js dosyaları birbiri arasında kullanabilmeniz için başka dosyada kullanacağınız componenti export etmeniz ve export ettiğiniz componenti kullanacağınız dosyaya import etmeniz gerekmektedir. Bunların yapılışı ise aşşağıdaki örnekte göserilmiştir.
import React from 'react';
import ReactDOM from 'react-dom';
import { NavBar } from './NavBar';
class ProfilePage extends React.Component {
render() {
return (
<div>
<NavBar />
<h1>All About Me!</h1>
<p>I like movies and blah blah blah blah blah</p>
<img src="https://s3.amazonaws.com/codecademy-content/courses/React/react_photo-monkeyselfie.jpg" />
</div>
);
}
}
ReactDOM.render(
<ProfilePage />,
document.getElementById('app')
)
import React from 'react';
export class NavBar extends React.Component {
render() {
const pages = ['home', 'blog', 'pics', 'bio', 'art', 'shop', 'about', 'contact'];
const navLinks = pages.map(page => {
return (
<a href={'/' + page}>
{page}
</a>
)
});
return <nav>{navLinks}</nav>;
}
}
Gördüğünüz gibi NavBar componentimizi ProfilePage in içerisinde kullanacığımız için component tanımının başında export ettik ve kullanacğımız ProfilePage dosyası içerisinde import ettik ve profil sayfamızda navbarımızı çağırmış olduk ve bunu react kullanarak yaptık.
Peki nedir bu import export?
Componentlarımızı projemiz içerisinde ayrı bir klasörde ayrı js uzantılı dosyalarda oluşturduk ve iki farklı componentimizi tanımladık diyelim siz bunları import ve export ile birbirine bağlamadığınız sürece onlar birbirlerini tanıyamazlar ve birbirlerinin bilgisini kullanamazlar.
Çok kaba bir tabirle export ettiğiniz component'a odasından çıkıp proje içinde dolaşmasına izin verirsiniz ama projede kapalıyken gözü bağlıdır. import ederkende kolundan tutup istediğiniz odaya sokup yapması gereken işi yaptırabilirsiniz.
Bu tip componentlar ise component olarak değil bir fonksiyon olarak yazılan componentlardır ve aynı component şeklinde kullanılabilir bir önceki bölüm ile çok benzer bir örnek vermek gerekirse
import React from 'react';
import ReactDOM from 'react-dom';
import { NavBar } from './NavBar';
class ProfilePage extends React.Component {
render() {
return (
<div>
<NavBar />
<h1>All About Me!</h1>
<p>I like movies and blah blah blah blah blah</p>
<img src="https://s3.amazonaws.com/codecademy-content/courses/React/react_photo-monkeyselfie.jpg" />
</div>
);
}
}
ReactDOM.render(
<ProfilePage />,
document.getElementById('app')
)
import React from 'react';
const NavBar = () =>{
return (
<div>
<h3>NAVBAR</h3>
</div>
)
}
export default NavBar;
Bu örnekte ise yukarıdakinden farklı olarak arrayde bulunan navbar elemanları yerine sadece basit bir NAVBAR yazısı bastıracaktır.
aşşağıda bulunan farklı export etme şeklini fark ettiniz mi bu şekilde de export yapılabiliyor.
Propslar kabaca componentler arasında veri akışı sağlayan react yapılarıdır denilebilir.
import React from 'react';
import ReactDOM from 'react-dom';
import { User } from './User';
class App extends React.Component {
render(){
return(
<div>
<User
name=" Cengizhan KÖSE "
school=" Beykoz UNI "
birth=" 2000 "
/>
</div>
);
}
}
import React from 'react';
import ReactDOM from 'react-dom';
export class User extends React.Component {
render(){
//Destructing:
const {name, school, birth} = this.props;
return(
<div>
<ul>
<li>İsim : {name}</li>
<li>Okul : {school}</li>
<li>Doğum Tarihi : {birth}</li>S
</ul>
</div>
);
}
}
User component ını çağırdığımız App componenti içerisinde Userı çağırırken verdiğimiz değerler class tarafından otomatik girdi olarak alınır bunlar props içerisinde tutulur ve girdi olarak alınan bütün değişkenlere this.props. değişkenin ismi olarak erişebiliriz. S Yukarıdaki örnekte ise tam olarak bu yapılmakta User componentını içerisine isim okulu ve doğum tarihini doğru formatta yolladığımızda ekrana isim okul doğumtarihi şeklinde bir unordered list bastıracaktır.
//Button.js
import React from 'react';
export class Button extends React.Component {
render() {
return (
<button onClick={this.props.onClick}>
Click me!
</button>
);
}
}
//Talker.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Button } from './Button';
class Talker extends React.Component {
handleClick() {
let speech = '';
for (let i = 0; i < 10000; i++) {
speech += 'blah ';
}
alert(speech);
}
render() {
return <Button onClick={this.handleClick}/>;
}
}
ReactDOM.render(
<Talker />,
document.getElementById('app')
);
yukarıdaki örnekte ise prop olarak bir metot gönderilmiştir ve bu metot buttona onClick eventi olarak bağlanmıştır böylelikle ekrandaki butona basıldığında handleClick metotu çalışacaktır.
Default props hiç bir prop girilmediği takdirde kabul edilecek değerlerdir PropTypes ise girilmesini istediğimiz propsun özelliklerini belirlemek için kullanılır.
import React from 'react';
import ReactDOM from 'react-dom';
class Button extends React.Component {
render() {
return (
<button>
{this.props.text}
</button>
);
}
}
// defaultProps goes here:
Button.defaultProps = { text: 'I am a button'}
//propTypes goes here:
Button.propTypes = { text: PropTypes.string.isRequired }
ReactDOM.render(
<Button />,
document.getElementById('app')
);
Gördüğünüz gibi bu örnekte button attribute olarak girilen değeri alıp üzerinde gösteriyor aşşağıda tanımladığımız defaultProps ile bir attribute girilmediğinde üzerinde yazacağı yazıyı ayarlamış olduk şuanda Buttonu rendera atarken herhangi bir text vermediğimiz için defaultprops çalışacak ve buttonun üzerinde atadığımız değer yazacak.PropTypes kısmında ise özellik olarak gönderilecek prop un string olmasını ve gönderilmesinin zorunlu olduğunu girdik. (Bütün PropTypelar için => Google)
Değişebilen bilgiye dinamik bilgi denir. React componentları render olmak için dinamik bilgilere ihtiyaç duyabilir. Herhangi bir oyunda skoru tutan component kullanıcı skor aldıkça değişecektir buradaki skor dinamik bir bilgidir. Bu component doğru bilgiyi render etmek için dinamik bilgiye ihtiyaç duyar.
Bir component'ın dinamik bilgiyi almasının iki yolu vardır props ve state.
Bu ikisinin dışında component içerisinde kullanılan her bilginin sabit kalması gereklidir.
import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component {
// constructor method begins here:
constructor(props){
super(props);
this.state = { title:'Best App' }
}
render() {
return (
<h1>
{this.state.title}
</h1>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('app')
);
state'leri yukarıda gösterildiği gibi constructor metotunun içerisinde tanımlayabiliriz. this.state yukarıda olduğu gibi bir objeye eşit olmalı bu obje kullanıldığı component'ın o anki durumunu (state) belirtir. Yukarıdaki örnekte state olarak girilen title ekrana h1 olarak gösterilmektedir.
React component'larının yukarıdaki gibi super() fonksiyonunu çağırmaları düzgün çalışması için önemlidir.(ES6 bilgisi=>Google=>super()function)
Kod içerisinde herhangi bir yerde state değeri setState ile değiştirilebilir.
import React from 'react';
import ReactDOM from 'react-dom';
const green = '#39D1B4';
const yellow = '#FFD712';
class Toggle extends React.Component {
constructor(props){
super(props);
this.state = { color: green };
this.changeColor = this.changeColor.bind(this);
}
changeColor(){
const newColor = this.state.color == green ? yellow : green;
this.setState({ color:newColor });
};
render() {
return (
<div style={{background: this.state.color}}>
<h1>
Change my color
</h1>
<button onClick={this.changeColor}>
Change color
</button>
</div>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('app')
);
Yukarıdaki örnekte tuşa basıldığında arka planın renginin değiştirilmesi changeColor() metotu içerisinde yazılmış ve bu metot ekrandaki butona onClick eventi ile bağlanmış artık buttona basıldığında arkaplanın rengi state yardımı ile yeşilden sarıya dönecektir.
//Parent.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Child } from './Child';
class Parent extends React.Component {
constructor(props){
super(props);
this.state = { name:'Frarthur' };
}
render(){
return(
<Child name={this.state.name} />
);
}
}
ReactDOM.render(
<Parent />,
document.getElementById('app')
);
//Child.js
import React from 'react';
export class Child extends React.Component {
render() {
return <h1>Hey, my name is {this.props.name}!</h1>;
}
}
örnek state projesine çok benzer olarak burada da iki component arasında state ve props kullanarak ekrana basit bir mesaj yazdırdık.Parent.js içerisinde state olarak belirli isimi Child.js e props olara yolluyor ve Child.js içerisinde o isime göre bir h1 tagi ekrana yazdırılıyor.
Bu projenin ikinic adımı olarak ekrandaki isimin bir dropdown menüden seçilen isimlere göre değşimesini ayarlayacağız ve burada child component parent componentinin state'ini değiştirecek.
//Parent.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Child } from './Child';
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = { name: 'Frarthur' };
this.changeName = this.changeName.bind(this);
}
changeName(newName) {
this.setState({
name: newName
});
}
render() {
return <Child name={this.state.name} onChange={this.changeName} />
}
}
ReactDOM.render(
<Parent />,
document.getElementById('app')
);
//Child.js
import React from 'react';
export class Child extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
const name = e.target.value;
this.props.onChange(name);
}
render() {
return (
<div>
<h1>
Hey my name is {this.props.name}!
</h1>
<select id="great-names" onChange={this.handleChange}>
<option value="Frarthur">
Frarthur
</option>
<option value="Gromulus">
Gromulus
</option>
<option value="Thinkpiece">
Thinkpiece
</option>
</select>
</div>
);
}
}
Parent.js dosyası içerisinde hazırladığımız changeName fonksiyonunu props olarak Child.js'e yolladık ve orada bir handle fonksiyonu yardımı ile onChange attribute'ünü verdik bu da menüden seçilen seçeneğin değerini alıp fonksiyonda changeName fonksiyonunu çağırarak Parent içerisindeki state i değiştiriyor ve ekrandaki isim değişiyor.
Her component kendi işine özgü olmalı fakat bu örnekte Child componenti hem state'i değiştiriyor hem de gösterme işini yapıyor bir sonraki adımda bu iki işi iki farklı alt componenta ayıracağız.
//Parent.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Child } from './Child';
import { Sibling } from './Sibling';
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = { name: 'Frarthur' };
this.changeName = this.changeName.bind(this);
}
changeName(newName) {
this.setState({
name: newName
});
}
render() {
return (
<div>
<Child onChange={this.changeName} />
<Sibling name={this.state.name} />
</div>
);
}
});
ReactDOM.render(
<Parent />,
document.getElementById('app')
);
//Child.js
import React from 'react';
export class Child extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
const name = e.target.value;
this.props.onChange(name);
}
render() {
return (
<div>
<select
id="great-names"
onChange={this.handleChange}>
<option value="Frarthur">Frarthur</option>
<option value="Gromulus">Gromulus</option>
<option value="Thinkpiece">Thinkpiece</option>
</select>
</div>
);
}
}
//Sibling.js
import React from 'react';
export class Sibling extends React.Component {
render() {
const name = this.props.name;
return (
<div>
<h1>Hey, my name is {name}!</h1>
<h2>Don't you think {name} is the prettiest name ever?</h2>
<h2>Sure am glad that my parents picked {name}!</h2>
</div>
);
}
}
Bu adımda görüldüğü gibi ana component'ımızda doğru bölümleri doğru component'lara props olarak yolluyoruz state değiştiren fonksiyonu bu işi yapan Child componentına değişen güncel ismi ekrana bastıracak olan Sibling componentına ise name state'ini yolluyoruz böylelikle daha temiz bir kodumuz oluyor.
React içerisinde style özellikleri tanımlamak için farklı yollar var. Bunlardan biri inline styles bu tür styling yöntemi yazılan elemente aynı satır içerisinde style tanımlanması anlamına gelir ve syntax'i şu şekildedir.
<h1 style={{ color: 'red' }}>Hello world</h1>
İki adet süslü parantez olmasının sebebi ilk süslü parantezler içindekinin jsx değil bir js olduğunu söylerken ikinci süslü parantezler ilk süslü parantezin içerisindekinin tam olarak bu olduğunu tanımlamasını sağlar.
{ color: 'red' }
Bütün styling işlemlerinizi inline style ile halledebilirsiniz ama stil öğeleri bir ikiden fazla olduğu zaman okunmada zorluk çıkarabiliyor. Bir başka styling metotu ise style öğelerini bir obje içerisinde tanımlayıp onu attribute olarak JSX içerisinde kullanmak.
import React from 'react';
import ReactDOM from 'react-dom';
const styles = {
background: 'lightblue',
color: 'darkred'
}
const styleMe = <h1 style={styles}>Please style me! I am so bland!</h1>;
ReactDOM.render(
styleMe,
document.getElementById('app')
);
style isminde bir değişkeni kodun en tepesinde tanımlamak bir çok javascript yazım şekli için iyi bir fikir olmayabilir ama React için hiçbir sıkıntı yoktur.
component'ın dışında global olarak tanımlayacağınız değişkenler o js dosyası için özel olacağı için her dosya içerisinde aynı styles isminde bir değişken oluşturup kullanabilirsiniz farklı js dosyaları içerisinde düzgün bir ayrım yapabilirseniz bir sıkıntı çıkarmayacaktır.
Normal javaScript kullanırken style lar ;
const styles = {
'margin-top': "20px",
'background-color': "green"
};
bu şekilde yazılırken React te camelCase kullanılarak yazılır;
const styles = {
marginTop: "20px",
backgroundColor: "green"
};
Normal JavaScript'te style değerleri genelde hep string olarak tanımlanır fakat React te px dışında bir birim verecekseniz stringe çevirmeniz gerekir
{ fontSize: 30 }
Burada React fontSize'ı otomatik olarak 30px olarak ayarlayacaktır
{ fontSize: "2em" }
ancak px kullanmak istemiyorsanız bu şekilde string olarak tanımlayabilir yanına da birimini yazabilirsiniz.string içerisinde px tanımlamakta çalışacaktır.
Style değişkenlerinizi ayrı bir dosyadan export ederekde kullanabilirsiniz bu aynı style'ı birden fazla component içinde kullanacağınız zaman çok işe yarayabilir.
//Style.js
const fontFamily = 'Comic Sans MS, Lucida Handwriting, cursive';
const background = 'pink url("https://codecademy-content.s3.amazonaws.com/programs/react/images/welcome-to-my-homepage.gif") fixed';
const fontSize = '4em';
const padding = '45px 0';
const color = 'green';
export const styles = {
fontFamily: fontFamily,
background: background,
fontSize: fontSize,
padding: padding,
color: color
}
//AttentionGrabber.js
import React from 'react';
import { styles } from './styles';
const h1Style = {
color: styles.color,
fontSize: styles.fontSize,
fontFamily: styles.fontFamily,
padding: styles.padding,
margin: 0
};
export class AttentionGrabber extends React.Component {
render() {
return <h1 style={h1Style}>WELCOME TO MY HOMEPAGE!</h1>;
}
}
//Home.js
import React from 'react';
import ReactDOM from 'react-dom';
import { AttentionGrabber } from './AttentionGrabber';
import { styles } from './styles';
const divStyle = {
background: styles.background,
height: '100%'
}
export class Home extends React.Component {
render() {
return (
<div style={divStyle}>
<AttentionGrabber />
<footer>THANK YOU FOR VISITING MY HOMEPAGE!</footer>
</div>
);
}
}
ReactDOM.render(
<Home />,
document.getElementById('app')
);
Component container'larını componentlardan ayırmak populer bir React kodlama yaklaşımıdır. Bu yaklaşımın arkasındaki mantık oldukça basittir ve şöyledir eğer bir component içerisinde state bulunduruyor ve mantıksal kodlamalar işlemler barındırıyorsa bu componentin render işlemini aynı component içerisinde yapmamak gerekir bunun yerine aynı componentin container'ı oluşturulur ve bütün mantık bulunan kısımları bu container içerisinde tutulur.
//GuineaPigs.js
import React from 'react';
const GUINEAPATHS = [
'https://s3.amazonaws.com/codecademy-content/courses/React/react_photo-guineapig-1.jpg',
'https://s3.amazonaws.com/codecademy-content/courses/React/react_photo-guineapig-2.jpg',
'https://s3.amazonaws.com/codecademy-content/courses/React/react_photo-guineapig-3.jpg',
'https://s3.amazonaws.com/codecademy-content/courses/React/react_photo-guineapig-4.jpg'
];
export class GuineaPigs extends React.Component {
render() {
let src = this.props.src;
return (
<div>
<h1>Cute Guinea Pigs</h1>
<img src={src} />
</div>
);
}
}
//GuineaPigsContainer.js
import React from 'react';
import ReactDOM from 'react-dom';
import { GuineaPigs } from '../components/GuineaPigs'
const GUINEAPATHS = [
'https://s3.amazonaws.com/codecademy-content/courses/React/react_photo-guineapig-1.jpg',
'https://s3.amazonaws.com/codecademy-content/courses/React/react_photo-guineapig-2.jpg',
'https://s3.amazonaws.com/codecademy-content/courses/React/react_photo-guineapig-3.jpg',
'https://s3.amazonaws.com/codecademy-content/courses/React/react_photo-guineapig-4.jpg'
];
class GuineaPigsContainer extends React.Component {
constructor(props) {
super(props);
this.state = { currentGP: 0 };
this.interval = null;
this.nextGP = this.nextGP.bind(this);
}
nextGP() {
let current = this.state.currentGP;
let next = ++current % GUINEAPATHS.length;
this.setState({ currentGP: next });
}
componentDidMount() {
this.interval = setInterval(this.nextGP, 5000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
const src = GUINEAPATHS[this.state.currentGP];
return <GuineaPigs src={src} />;
}
}
ReactDOM.render(
<GuineaPigsContainer />,
document.getElementById('app')
);
Görüldüğü gibi bu örnekte GuineaPigs.js dosyasının içerisinde sadece render işlemi bulunuyor container'ında ise resimin zamana bağlı değişmesini sağlayan mantıksal işlemler bulunur ve bunlar birbirlerinden props ve stateler aracılığıyla iletişime geçerler.
container olarak ayırdığınız componentlarda render componentları eğer render edilecek JSX i return etmek dışında bir işlem gerçekleştirmiyorsa (ki bu şekilde olmalıdır) render componentınızı fonksiyonel componenta çevirmek bir React programlama yaklaşımıdır. Bir önceki başlığın örneğini çevirmek gerekirse GuineaPigs.js dosyasının içeriği şuna dönüşür.
import React from 'react';
export const GuineaPigs = (props) => {
return (
<div>
<h1>Cute Guinea Pigs</h1>
<img src={props.src} />
</div>
);
}
render fonksiyonunun gittiğini fark etmişsinizdir ve propsu fonksiyona input olarak yazdık fonksiyonel component içerisinde de this yapısını kullanmadık.
import React from 'react';
import ReactDOM from 'react-dom';
export class Input extends React.Component {
constructor(props){
super(props);
this.state = { userInput: ''};
this.handleUserInput = this.handleUserInput.bind(this);
}
handleUserInput(e) {
this.setState({
userInput: e.target.value
});
}
render() {
return (
<div>
<input type="text" onChange={this.handleUserInput} value={this.state.userInput} />
<h1>{this.state.userInput}</h1>
</div>
);
}
}
ReactDOM.render(
<Input />,
document.getElementById('app')
);
Bu örnekte ise bir input formuna onChange fonksiyonu atadık ve bu fonksiyonun input olarak girilen verinin component'ın userInput state'ini değiştirmesini sağladık en son adım olarak bu state'i h1 tagleri ile ekrana bastırmak kaldı.
React formlarında iki farklı terim vardır bunlar controlled ve uncontrolled component diye geçer.
Uncontrolled component kendi state'ini tutan component olarak isimlendirilebilir.Controlled component kendi state'ini bulundurmaz dışarıdan biri tarafından kontrol edilir.
<input type='text' />
Bu basit text inputunun o anda içinde ne olduğunu öğrenmek isterseniz inputa şu şekilde sormanız mümkün
let input = document.querySelector('input[type="text"]');
let typedText = input.value; // input.value değeri text box içerisindeki anlık texte eşit olacaktır.
Şuanda input içerisinde bulunan anlık text'i ona sorduğunuzda size verecektir fakat burada bunu uncontrolled yapan durum kendi stateini kendisi hatırlaması ve takip etmesidir.
controlled component'lar kendi hafızası bulunmaz içerisindeki anlık değeri sorduğunuzda bu bilgiyi props ile ulaşır ve çoğu react component bu şekilde çalışmaktadır. React'te bir inputa value attribute verdiğiniz zaman o input controlled hale gelir kendi hafızasını kullanmayı bırakır.
Lifecycle methodları componentin "hayatı" içerisinde belli anlarda çağırılan methodlardır. Bu methodlar ile componentiniz çağırılmadan hemen önce ne olacağını belirleyebilir çağırıldıktan hemen sonra ne olacağını ya da çağırıldığı anda olacakları belirleyebilirsiniz. Bu metotları bir sürü farklı an için ekleyebilirsiniz ve kullanıldığında çok güçlü methodlardır.Lifecycle metotları toplamda üç çeşittir; mount, update ve unmount
Component'in mount olduğu zaman ilk defa render edildiği zamandır ve bu sırada arka arkaya üç lifecycle metotu bu sırayla çalışır;
- componentWillMount
- render
- componentDidMount
Component render edilmeden hemen önce çalışacak olan metottur component render edilmeden önce bir olay olmasını istersek buraya yazabiliriz.
Render fonksiyonunu notlar içerisinde bir çok defa anlattım. Ama basitçe componentin ekrana render edilmesini sağlayan metot. render işlemi bu etapta gerçekleşir ve render edilecek elemanlar burada belirtilir.
Componentin render işlemi tamamlandıktan sonra devreye girer ve render işleminden sonra çalışması istenilen bölümler buraya yazılır.
Component ilk render olduğu zaman update olmaz.ilk renderdan sonra her tekrardan render edilişinde update olmuş olacak ve her render işleminde sırasıyla şu beş lifecyle metotu çalışır.
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
- render
- componentDidUpdate
Component update olduğunda props almışsa tekrar render edilmeden önce çalışacak olan metottur.Component propsa sahpi değilse bu metot çağırılmaz
Component update olduğunda render edilmeden önce çalışan bir metottur. bu metot true veya false değer döndürmelidir eğer bu fonksiyon true dönerse bir sıkıntı olmaz fakat false döndüğünde update gerçekleşmez.
Component render edilmeden önce çalışan son metottur ve otomatik olarak iki argüman alır nextProps, nextState
Bu metot içerisinde setState tanımlayamazsınız daha çok react dışında kısmıları yapmak için iyi bir bölümdür API istekleri gibi.
Component render edilir.Sırayı belirtsin diye ekliyorum render aynı işi yapar.
Component update sürecinin son metotudur rerender işlemi bittikten sonra çağırılır ve otomatik olarak iki argüman alır prevProps, prevState bunlar componentin update başlamadan önceki props ve state değerlerini tutar ve burada onları güncel değerler ile karşılaştırabiliriz.
Bu metotla component DOM üzerinden kaldırıldığında neler olacağını belirleyebiliriz.
import React from 'react';
import ReactDOM from 'react-dom';
class Contact extends React.Component {
constructor(props) {
super(props);
this.state = {
password: 'swordfish',
authorized: false
};
this.authorize = this.authorize.bind(this);
}
authorize(e) {
const password = e.target.querySelector(
'input[type="password"]').value;
const auth = password == this.state.password;
this.setState({
authorized: auth
});
}
render() {
return (
<div id="authorization">
<h1>Contact</h1>
<ul>
<li>
[email protected]
</li>
<li>
555.555.5555
</li>
</ul>
</div>
);
}
}
ReactDOM.render(
<Contact />,
document.getElementById('app')
);
İstenen yukarıda contact bilgilerini basan kartın authorize ın doğru olduğu takdirde görünür olması doğru değilse belirlenen passwordu sorması.
ÇÖZÜM:
import React from 'react';
import ReactDOM from 'react-dom';
class Contact extends React.Component {
constructor(props) {
super(props);
this.state = {
password: 'swordfish',
authorized: false
};
this.authorize = this.authorize.bind(this);
}
authorize(e) {
const password = e.target.querySelector(
'input[type="password"]').value;
const auth = password == this.state.password;
this.setState({
authorized: auth
});
}
render() {
const login = (
<form action = "#" onSubmit = {this.authorize}>
<input type = "password" placeholder = "Password"/>
<input type = "submit"/>
</form>
);
const contactInfo = (
<ul>
<li>
[email protected]
</li>
<li>
555.555.5555
</li>
</ul>
);
return (
<div id="authorization">
<h1>{this.state.authorized ? 'Contact' : 'Enter a Password'}</h1>
{ this.state.authorized ? contactInfo : login }
</div>
);
}
}
ReactDOM.render(
<Contact />,
document.getElementById('app')
);
ve artık şifre girişi yapılmadığı takdirde contacts bilgileri ekranda görünmeyecektir peki bu örneğin çözümündeki kod nasıl çalışıyor?
öncelikle Contact adında bir componentimiz var ve bu componentin üç ana metotu var bunlar .constructor() .authorize() ve .render() constructor OOP den bildiğimiz yapıcı fonksiyon authorize yapıcı fonksiyonda girilen default şifre değerinin kullanıcının girdiği şifre ile aynı olması durumunda constructorda bulunan authorized booleanını değiştiren bir method render ise react de kullandığımız render metotu örneğin ilk halindeki render fonksiyonunda bir kaç değişiklikle bu sorunu çözdüğümüzü fark etmiş olabilirsiniz öncelikle giriş yapılmadıysa ekrana çıkacak olan formu bir değişken tanımlayarak (login) JSX formunun kodlarını yazdık sonrasında formda bulunan contact bilgilerini alıp contactInfo adında bir değişkene atadık ve bu iki JSX tutan değişkeni return içerisinde bir ternary operator ile ayırarak authorized true ise contactInfoyu false ise logini yansıttık. Tabi başlığıda aynı şekilde bir ternary operator ile ayırdık ve authorized ın false olduğu durumda yansıttığımız formun çalışması için forma onSubmit adında bir event ekledik bu evente de authorize fonksiyonumuzu bağladık bu şekilde buttona basıldığında girilen şifre doğru ise contact bilgileri yansıtılıyor yanlış ise hiçbir şey olmuyor.
//Button.js
import React from 'react';
export class Button extends React.Component {
render() {
return (
<button onClick={this.props.onClick}
className={ this.props.light ? 'light-button' : 'dark-button' }>
Refresh
</button>
);
}
}
//Random.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Button } from './Button';
class Random extends React.Component {
constructor(props){
super(props);
this.state = { color: [0, 126, 127] }
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
this.setState({color:this.chooseColor()});
}
componentDidMount() {
this.applyColor();
}
componentDidUpdate(prevProps, prevState) {
this.applyColor();
}
formatColor(ary) {
return 'rgb(' + ary.join(', ') + ')';
}
isLight() {
const rgb = this.state.color;
return rgb.reduce((a,b) => a+b) < 127 * 3;
}
applyColor() {
const color = this.formatColor(this.state.color);
document.body.style.background = color;
}
chooseColor() {
const random = [];
for (let i = 0; i < 3; i++) {
random.push(Math.floor(Math.random()*256));
}
return random;
}
render() {
return (
<div>
<h1 className={this.isLight() ? 'white' : 'black'}>
Your color is {this.formatColor(this.state.color)}.
</h1>
<Button
light={this.isLight()}
onClick={this.handleClick} />
</div>
);
}
}
ReactDOM.render(
<Random />,
document.getElementById('app')
);
Bu projede random fonksiyonu içerisinde button.js içerisindeki componenti kullanarak bir button oluşturuyor ve state ve propsların yardımı ile arkaplanın rengini her buttona basıldığında random bir şekilde seçip ekrana rgb değerlerini yazdırarak arkaplanı o renge çeviriyor.
//App.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Video } from './Video';
import { Menu } from './Menu';
const VIDEOS = {
fast: 'https://s3.amazonaws.com/codecademy-content/courses/React/react_video-fast.mp4',
slow: 'https://s3.amazonaws.com/codecademy-content/courses/React/react_video-slow.mp4',
cute: 'https://s3.amazonaws.com/codecademy-content/courses/React/react_video-cute.mp4',
eek: 'https://s3.amazonaws.com/codecademy-content/courses/React/react_video-eek.mp4'
};
class App extends React.Component {
constructor(props) {
super(props);
this.state = { src: VIDEOS.fast };
this.chooseVideo = this.chooseVideo.bind(this);
}
chooseVideo(newVideo) {
this.setState({
src: VIDEOS[newVideo]
});
},
render() {
return (
<div>
<h1>Video Player</h1>
<Menu chooseVideo={this.chooseVideo} />
<Video src={this.state.src} />
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('app')
);
//Video.js
import React from 'react';
export class Video extends React.Component {
render() {
return (
<div>
<video controls autostart autoPlay muted src={this.props.src}/>
</div>
);
}
}
//Menu.js
import React from 'react';
export class Menu extends React.Component {
constructor (props){
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(e){
const text = e.target.value;
this.props.chooseVideo(text);
}
render() {
return (
<form onClick={this.handleClick}>
<input type="radio" name="src" value="fast" /> fast
<input type="radio" name="src" value="slow" /> slow
<input type="radio" name="src" value="cute" /> cute
<input type="radio" name="src" value="eek" /> eek
</form>
);
}
}
Bu örnekte ise ana componentımız içerisinde bir başlık bir menü ve bir video componenti bulunmakta menü videoyu seçerken video componenti ise seçilen videonun açılmasından sorumlu olarak çalışmakta state ve propslar adına güzel bir çalışma.