19 Ocak 2021 Salı

React Eğitiminden Notlar

      S.A. Arkadaşlar,

      Son dönemlerde üzerinde çalıştığım react konusunda bazı notlar topladım. Daha önce de bu tarz javascipt ve angular(1, 2, 3) eğitim notlarım olmuştu. Bu sefer de react konusunda aldığım ve Ali Somay'ın aldığı notları birleştirerek yazıya almaya karar verdim. Ayrıca yazıyı gözden geçiren Damla Köksal'a da teşekkürlerimi iletmek isterim. Bununla birlikte github üzerinde bir proje de paylaşıyorum. Zaman içerisinde geliştirmeler yapmaya devam edeceğim. Hazırsak başlayalım.

     Component yapısı: Angular'da da bulunan component bazlı yapı bulunmaktadır. Sınıf ve fonksiyon bazlı 2 ayrı component yapısı bulunmaktadır. Eskiden yaygın olan sınıf yapısı olsa da fonksiyon da kullanım kolaylığından dolayı son dönemlerde kullanımı her geçen gün artmaktadır. Angular'dan farklı olarak one-way data-binding yapısı kullanılmaktadır. Tutulan verinin view tarafına aktarılma konusudur. Farklı şekillerde two-way de desteklenmektedir. Ayrıca burada göz önünde bulundurmamız gereken en önemli konulardan biri de sadece parent component'ten child component'lere veri akışı vardır. Bununla birlikte basit ve çok kullanılan yöntemlerle aksi akış da sağlanmaktadır. Bunun için de ilerleyen süreçlerde farklı geliştirmeler de oldu. Bu konuya tekrar değineceğiz.

      Sınıf Bazlı Component: Sınıf bazlı component yapısı react içerisinde gelen Component'i kalıtır. React ile birlikte eskiden daha çok kullanılan olan component yapısıdır. Yeni gelen gelişmelerle birlikte kullanım oranı düşmektedir.  Kullanılma oranın düşüşte olması, ileride inceleyeceğimiz fonksiyonel component ile kullanımı daha kolay olan Hooks yapısıdır.

import React, { Component } from "react";

class ClassComponent extends Component {
 render() {
   return <h1>Hello, world</h1>;
 }
}

      Fonksiyonel Component: Modern react uygulamalarında sık kullanılan iki yöntemden biridir. Aslına bakıldığında bir javascript fonksiyonudur ve dönüşünde yine bir react component'i döndürür. [Daha fazlası]

import React from "react";

function FunctionalComponent() {
 return <h1>Hello, world</h1>;
}

     JSX yapısı (JavaScriptXml): React component'leri üretmek için kullanılan bir syntax'tır. Html gibi gözükse de aslında html değildir. JSX kullanmak zorun değiliz, fakat html yapısına oldukça benzediğinden kullanım kolaylığı bulunmaktadır. Daha sonra bu kodlar render edilir ve html formatına ayrıca çevirilir. Bu arada en dışarıda yalnızca bir component bulunur ve diğer tüm component'ler burada yer alır. Aksi durumda hata ile karşılaşacaksınız. [Daha fazlası]

      Props: Property kelimesinin kısası olan prop içinde bulunduğu component'in özelliğini taşıyan bir component'ten diğerine veri, event taşımak için kullanılan salt okunur bir yapıdır. Kullanımı sonrası  <CategoryList> yerine <CategoryList title="data"> gibi bir yol izliyoruz. React'in eski sürümlerinde constructor içinde tanımlası ve parent class'a gönderilmesi gerekiyordu, fakat yeni sürümlerle birlikte artık böyle bir tanımlamaya gerek kalmamıştır. Bu tarz kullanımlar görürseniz şaşırmayın lütfen.  

constructor (props){
   super(props);
}

    State: Bir component'in datasıdır. Component içerisinde veriyi saklamak ve o anki durumunu gösteren yapılardır. Kullanımı aşağıdaki gibidir.

this.state = {date: new Date()};

render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }

     Props ve state birbirine karışabilen 2 kavramdır. İkisinin birbirinden farkları vardır. İkisini anlatıp karşılaştıran şu yazıya bakmanızı şiddetle tavsiye ederim. [Dahası]

    Event'larla çalışmak:  DOM üzerinde oluşan event'lerle benzerlik göstermektedir.  Burada arrow function kullanılması öne çıkmaktadır. Bu doğru bir şekilde kavranmış ise react tarafında event'lerle çalışmak daha da kolay olacaktır.

handleClick = () => {
    console.log('clicked');
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }

     React yaşam döngüsü:  React'ta yaşam döngüsünü temel olarak 4 adımdan oluşmaktadır. Bunlar:

         Initialization: Başlangıç adımıdır. Constructor içerisinde state ve props ayarlanarak başlar.

         Mounting: Oluşturulan react bileşenlerinin DOM'e bağlandığı aşamadır.

         Updating: Herhangi bir nedenden dolayı oluşan güncellemelerin ele alındığı aşamadır.

         Unmounting: Oluşturulan bileşenlerin DOM'dan ayrıldığı aşamadır. 

      Şematik olarak incelemek isterseniz Türkçe dil desteği de olan linke göz atmanızı tavsiye ederim.

    Routing: SPA'larda eski yapılara(mvc - action) göre daha farklı olmaktadır. Routing işlemi component'ler arası geçişler mevcuttur. React tarafında bu işi yapan react-router-dom kütüphanesidir. Router, route ve switch componentleri bu işlemleri yapmakla alakalıdır. [Daha fazlası]

     Redux: React içerisinde bütün bileşenler birbiriyle haberleşmektedir, fakat bu haberleşme parent'ten child'a doğru olmaktadır demiştik. Redux ise bize bu kolaylığı sağlamaktadır. Her hangi bir bileşenden diğerine geçiş rahatlıkla olabilmektedir. Ayrıca state'leri tek bir yerden yönetebiliyoruz. [Daha fazlası] Redux konusunda bilinmesi gereken en önemli 3 kavram ise aşağdaki gibidir : 

     Action: Reducer'a ulaşarak store'deki veriyi günceller. Action ve reducer'ler için mümkün olduğunca modüler düşünmek gerekir. Action tanımlarken kendilerini döndüren fonksiyonlar aynı dosyada yazılabilir. Böylece payload'ı o fonksiyona verdiğimizde farklı payload'lar için aynı action'ı döndürür. Bunu da dispatch içerisinde çağırabilir ve kendi özel action'ımızı dispatch edebiliriz. Aşağıda belirtilen şekilde kategorize edilebilir.

// Action türü.
export const UPDATE_ELMA = '@elma/update';

// Elma çeşitleri
export type ElmaType = "amasya" | "fuji"

// Action tanımı
export interface UpdateElmaAction {
  type: typeof UPDATE_ELMA;
  payload: ElmaName;
}

// Action döndüren fonksiyon 
export const updateElmaAction = (
  payload: UpdateElmaAction['payload']
): UpdateElmaAction => ({
  type: UPDATE_ELMA,
  payload
});

export type ElmaActionTypes = UpdateElmaAction

    Reducer: Action'a ulaşarak gerekli güncellemeyi yapmak için kullanılır. Veri değişimini sağlayarak store'u günceller. Reducer'leri konularına göre ayırtmak yönetebilirlik açısından iyi olacaktır. Burada immutable operasyonları kolaylaştırmak için immer.js kullanılabilir.

//combineReducers ile tüm reducer'leri tek bir çatı altına topluyoruz.
import { combineReducers } from 'redux';
import { ElmaReducer } from './elma';

const elmaReducer = combineReducers({
  elmaState: ElmaReducer,
  // Buraya böyle devam ederek eklenebilir.
});
export const rootReducer = combineReducers({
  meyveler: elmaReducer,
  // sebzeler vb.. Böylece state'i organize edebiliriz.. 
});

export type RootState = ReturnType<typeof rootReducer>;
//elma reducer
// Yeni bir immutable state ile eskisini değiştirirken işimizi kolaylaştıracaktır.
import produce from 'immer';
// Gerekli tipleri alıyoruz.
import { UPDATE_ELMA, ElmaType, ElmaActionTypes } from '../actions/elma-actions';

// State'imizi tanımlayalım.
export interface ElmaState {
  tur:ElmaType;
  // Devam edebilir..
}

// Default state
const initialState: ElmaState = {
  tur: "amasya" 
};

// Reducer bize yeni bir state döndürecek.
export const ElmaReducer = (
  state = initialState,
  action: ElmaActionTypes,
): ElmaState => {
  // Immer.js bu işi bizim için daha pratik bir hale getiriyor.
  return produce(state, (draft: ElmaState) => {
    switch (action.type) {
      case UPDATE_ELMA:
        // Taslaktaki değerleri mutate ettiğimizde immer bizim için arkada yeni bir immutable state oluşturup bunu döndürüyor.
        draft.tur = action.payload;
        return;
      default:
        console.log('Reducer called.');
    }
  });
}

        Store: Redux ile gelen verileri tutacağımız alan diyebiliriz. Bütün verileri tek bir yerde tüm bileşenlerden bağımsız olarak tutacağımız için bunlara erişim çok daha kolay olacaktır.    

//store dosyamızı oluşturuyoruz.
import { createStore/*, applyMiddleware, compose*/ } from 'redux';
import { rootReducer } from './reducers/root';

// eslint-disable-next-line @Typescript-eslint/explicit-function-return-type
export const store = (() => {
  const s = createStore(
    rootReducer,
    // Eğer middlewarelerimiz olsaydı aşağıdaki gibi yapabilirdik.
    /* compose(applyMiddleware(someMiddleWare)), */
  );
  return s;
})();

    Redux Thunk: Saf olmayan fonksiyonları saf bir şekle dönüştürmeyi sağlar. Asenkron ve yan etkiye sahip olabilecek metodları bu middleware aracılığıyla korumamız lazım. Bu sayede draw back yan etkilerini engellemesini sağlar. Ayrıca middleware yapısı action yerine  fonksiyon dönme ayrıcalığı tanır. Bununla birlikte kodun okunmasını kolay kılar ve unit testleri daha rahat bir şekilde yazmayı sağlar.[Daha fazlası]

    Hata yönetimi: Bileşenlerde meydana gelenler hataları yakalamak ve bunu ön tarafta göstermek amacıyla kullanılan genel bir yapıdır. Burada farklı çözümler bulunmaktadır. Burada bu konuyla ilgili ayrıntılı bir yazı ele alınmaktadır.

   Hooks: Sektörde hem class component kullanımı hem de fonksiyonel component yapısı oldukça yaygındır, fakat son dönemlerde hooks ile birlikte fonksiyon component yapısı belirgin olarak artış göstermektedir. Bunun sebebi, fonksiyonel component'i desteklemesi, kolay kullanım ve life cycle tek bir işlem olarak yürütmesi olarak gösterilebilir. Hooks referans tipli bir değişkende fonksiyonu tutabilmektedir. Arrow function ile kullanımı da oldukça basit bir hale gelmektedir. Ayrıca sadece parametre geçirerek this.props özelliği de kullanılmaktadır.

const textInput = () => {
   //kodlar
}

  Kısa Kısa

   export:  Nesne yönelimli dillerde bulunan public tanımlayıcısı ile benzer görev görmektedir.

   react strap: Material ve boostrapt gibi alternatifleri olan css çatısıdır. 

   this: C#, Java gibi dillerde bulunduğu class'ı, javascript'te ise parent class'ı işaret eder.

   fetch: Javascript ile ilgili olan API tarafından veriyi alıp göndermeye yarayan yapı.

   axios: fetch için kullanılabileceğimiz en iyi kütüphanelerden biridir.

   component drilling:  Verinin bir bileşenden diğerine sadece parent'ten child'a aktarılmaktadır. Aynı hiyerarşideki bir bileşende veriyi kullanmak için onu parent bileşinine taşınmasına denir. 

   useEffect: Life cycle işlerini tek operasyonda toparlanmıştır.

   useState: setState yerine kullanılır.

   react-saga: Veri tabanındaki uzun işlemlerde oluşabilecek hataları engellemek için kullanılır.

   react-observable: async operasyonlar veya actionlari transform etmek için kullanılır.

   Dom-Virtual Dom: Web sayfalarının görüntülenmesi için oluşan hiyerarşik yapıdır. Sanalın farkı ise tüm sayfayı render etmek yerine sadece belirli olan yeri değiştirerek gereksiz hantallıktan kurtulur.

    Bakılması gereken linkler:

https://tr.reactjs.org/docs - React'in türkçe olarak hazırladığı resmi dokümantasyon

https://medium.com/kocsistem/a-dan-z-ye-react-facce30533d0 - Yavuz Akıncı tarafından hazırlanan ve  Koç sistem medium kanalında yayımlanan oldukça değerli ve derli toplu bir yazı

http://devnot.com/2018/redux-nedir/ - Devnot ekibi tarafından derli toplu olarak hazırlanmış güzel bir yazı

Hiç yorum yok:

Yorum Gönder