innovance

First of all, what’s my motivation to write this article? I needed to use sliding background animation for a cool display on my website. I know there are some carousel components in the ecosystem but I couldn’t find a drag-and-drop solution to my situation. What I need is sliding background animation, when a different route is selected (yes, react-router also exists!).

I encountered a few problems during this journey. Articles I found using react-addons-css-transition-group which is moved to react-transition-group according to the official documentation. Secondly, I struggled with new documentation of the package. I had few trial and error cases until I leaned back with satisfaction.

Maybe, this article will be your drag-and-drop solution in your projects. That’s why I’m writing right now. Let’s get started.

In my scenario, I want to change the background image with every route change. It can be done by using path specific images with react-router. However, I want to add a smooth change between images. The solution is CSS transition but how can I force to animate background images programmatically?

First, I should tell when the transition happens to react-transition-group. It happens when background.path is changed. Background data of the demo is below:

{
path: "/",
src: "http://sorblog.com/wp-content/uploads/2018/10/javascript-autoclick.jpg"
},
{
path: "/react",
src: "https://cdn-images-1.medium.com/max/1200/1*jDIj2SKAE-Bp32owLoHDjw.png"
},
{
path: "/transition",
src: "https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2016/09/1475177859css.jpg"
}

The important part is change of CSSTransition’s key prop. When key changes, the current background goes into an exiting state and the incoming one goes into an entering state. You can see the transition in slow-motion (total transition duration 5000ms):

Below implementation express how it should be in action:

const Background = () => {
const location = useLocation();
const background = backgrounds.find(bg => bg.path === location.pathname); return (
<div>
<TransitionGroup>
<CSSTransition
classNames="slide"
timeout={{ enter: 1000, exit: 1000 }}
key={background.path}
>
<img
className="background"
src={background.src}
alt={background.path.slice(1)}
/>
</CSSTransition>
</TransitionGroup>
</div>
);
};

Last part is writing proper css rules to meet our desired transition. Rules should include slide in it and transtion durations should be compatible with timeout prop of CSSTransition.

/* ANIMATIONS */
.slide-enter {
transform: translateX(100%);
}.slide-enter-active {
transform: translateX(0%);
transition: transform 1000ms ease-in-out;
}.slide-exit {
transform: translateX(0%);
}.slide-exit-active {
transform: translateX(-100%);
transition: transform 1000ms ease-in-out;
}

The demo display is below with routing and navigation. Each route has a different background and changing route cause background transition: https://codesandbox.io/embed/pk81k02xjm?fontsize=14&hidenavigation=1&theme=dark

PS: I don’t know why but inside the sandbox transitions don’t look as intended so you can check on https://pk81k02xjm.csb.app/

Author: Özgün Bal

Geçtiğimiz hafta React Ekibi tarafından paylaşılan bir makale; komünite ve UI geliştiricileri tarafından oldukça heyecanla karşılandı. Bu heyecanın nedeni de; genel olarak UI kütüphanelerinin çalışma prensiplerinin yarattığı en büyük problemlerden birisinin ortadan kaldırmak adına yapılan çalışmalar. “Blocking Rendering” olarak isimlendirilen problem, React’ın yeni bakış açısıyla tasarladığı “Concurrent Mode” ile ortadan kalkıyor. Peki, “Blocking Rendering” nedir, “Concurrent Mode” bu problemi ortadan nasıl kaldırıyor? Birlikte inceleyelim.

Blocking Rendering

Günümüzde UI kütüphaneleri, tarayıcıyı senkronize şekilde günceller. Örneğin bir ekranı açmak istediğimizde, UI kütüphanesi DOM’daki bu değişiklikleri ekrana tek seferde yansıtmak ister. Örneğin içerisinde liste olan bir ekranı açmak için, liste componentini render etmeye başlar, bu render işlemi bitene kadar da ekranda başka hiçbir şey yapılmaz. Şimdi bu listenin 500.000 elemanı olduğunu düşünelim. Ekranda herhangi bir etkileşim yaratabilmek için, maalesef bu listedeki tüm elemanlar render olana kadar beklemek zorundayız.

Peki bu listenin üzerine bir de filtre eklediğimizi düşünürsek ne olur? Filtrenin çalışacağı text input içine yazdığımız herhangi bir harfin gözükmesi için, bu devasa bekleme süresi tekrar devreye girer. Bu bekleme ve ekranda beliren sürekli takılarak çalışma hissi, kullanıcı deneyimini tamamen olumsuz bir algıya dönüştürebilecek problemler silsilesine yol açmış olur.

Interruptible Rendering

Bu problemleri şimdiye dek hiç yaşamadık mı ya da görmemezlikten mi geldik? Tabii ki hayır. Bir şekilde bu problemleri “halı altına süpürmek” için hali hazırda “Debouncing” ve “Throttle” gibi yöntemleri kullanıyorduk. Bunların ne olduğuna değinecek olursak; birden fazla yapılan sıralı fonksiyon çağrılarını teke indirmek için kullandığımız yöntem Debouncing, fonksiyon çağrısını etkileşimden bir süre sonra(delay) yapmak için kullandığımız yöntem de Throttling oluyor. Fakat bu yöntemler, filtre için text input içerisine bir şeyler yazarken listenin aynı kalmasının ya da gücü sınırlı cihazlarda takılma, bekleme gibi sorunların devam etmesinin önüne geçemiyor.

Çünkü rendering başladığı andan itibaren sonuna dek kesilemiyor. Bu nedenle text input içine yazdığımız harf her dokunuşta güncellenemiyor. Hangi UI kütüphanesini kullanırsanız kullanın, eğer kütüphane blocking rendering kullanıyorsa, büyük oradanki componentlerin yaşattığı bu sıkıntının da çözümü de kolay olmuyor.

Bu sorunlarla baş etmekte zorlanan Facebook ekibi, artık React kütüphanesinde Concurrent Mode ile kütüphanenin temelindeki limitlemeleri ortadan kaldırarak rendering’i interruptible hale, yani önceliklere göre araya girebilecek hale getiriyor.

Concurrent Mode

Önceliklerimiz önemlidir.

Concurrent ModeReact tarafından;

Concurrent Mode is a set of new features that help React apps stay responsive and gracefully adjust to the user’s device capabilities and network speed.” şeklinde açıklanmış. Bu tanımı, “React uygulamasını, kullanıcının cihaz yetenekleri ile ağ hızına göre her zaman cevap verebilir ve detaylıca ayarlanabilir hale getirecek özellikler seti.” olarak çevirsek sanırım hatalı olmaz. Concurrent Mode’u anlamaya çalışırken; teorik ve okunduğunda aslında çok da bir şey ifade etmeyen bu tanımdan ziyade, “önceliklendirme” kavramı ile birlikte düşünmenizi tavsiye ederim.

Yazının başında da bahsettiğim gibi Concurrent Mode olmadan React, tamamen bitene kadar rendering işine devam ediyordu ve rendering bitmeden diğer işlere sıra gelmiyordu.

Concurrent Mode ile React ise, hali hazırda rendering işi devam ederken eğer daha öncelikli bir iş gelirse, mevcut rendering’i kesebiliyor. Öncelikli işi araya alıp, bitirdikten sonra da rendering’e devam edebiliyor duruma geliyor. Yani bir bakıma, tamamen senkron yapıdan, asenkron olabilen bir rendering algoritması bizi bekliyor.

Bu öncelikli işler neler olabilir?

Bununla birlikte, başka bir önemli özellik daha var. Aslında o da günümüzdeki bir çok UI kütüphanesinin davranış biçimlerinden birisine efektif çözüm oluyor. Örneğin kullanıcı “Ana Sayfa” üzerinde beklerken, “Siparişlerim” butonuna tıklayarak o ekrana gitmek istiyor. Kullanıcı, bu sırada geliştirici ekibin kararına göre 2 farklı davranıştan birini görüyor. Uygulama ya kullanıcıya tüm bilgiler gelmeden örnek bir boş sayfa gösteriyor, ya da bilgilerin yavaşça dolmasını sağlayarak ekranın kullanıcı görürken şekillendiriyor.

React’ın yeni Concurrent Mode’u ile artı kullanıcı butona bastığı anda bellekte gidilmek istenen sayfayı render ederken, kullanıcı hali hazırda bulunduğu sayfada kalmaya devam ediyor. Ne zaman servis çağrıları ve resim yüklemesi gibi zaman alan işler biterse, kullanıcıya diğer sayfayı tamamen dolu haliyle o zaman açıyor. Bu sayede kullanıcı hiçbir zaman önünde şekillenen bir sayfa görmüyor. Bununla birlikte sayfa içerisinde “Loading” imajı da eklenirse, sorunsuz bir kullanıcı deneyimi halini almış alıyor. Bu sayede uygulamanın akışı ve cevap verebilirliği büyük ölçüde artıyor.

Bu günümüz koşullarında başka çözüm yolları ile yapılabilir olsa da, yönetimi zor ve karmaşık olan bir hale gelebiliyor. React Concurrent ModeReact içerisinde built-in yani dahili olarak gelerek bu sorunları merkezde çözmeyi hedefliyor.

Kod Örneği

import {
useState,
commonUpdate,
urgentUpdate
} from "sample-react";

function SlowAndLowPriorityComponent() {
const [someData, changeData] = useState(0);
return (
<div>
<BigComponentThatTakesVeryLongToRender someProp={someData} />
<button
onClick={() => {
commonUpdate(() =>
changeData(prevData => prevData + 1)
);
}}
>
Uzun süren ve düşük öncelikli güncelleme
</button>
</div>
);
}

function FastAndHighPriorityComponent() {
const [someData, changeData] = useState(0);
return (
<div>
<SmallComponentThatRendersFast someProp={someData} />
<button
onClick={() => {
urgentUpdate(() =>
changeData(prevData => prevData + 1)
);
}}
>
Hızlı ve acil güncelleme
</button>
</div>
);
}

function App() {
return (
<div>
<SlowAndLowPriorityComponent />
<FastAndHighPriorityComponent />
</div>
);
}

// Eğer kullanıcı önce SlowButLowPriorityComponent butonuna,
// ve sonrasında FastAndHighPriorityComponent butonuna tıklarsa;
// React SlowButLowPriorityComponent'inin renderingini durdurup,
// FastAndHighPriorityComponent'inin renderingini (yeni state ile)
// tamamlar. Sonrasında SlowButLowPriorityComponent değişikliğine
// devam eder.

Concurrent Mode’a Ne Denli İhtiyacımız Var?

Genel olarak altyapısal bir yeni özellik olan Concurrent Mode için, bana kalırsa React tabanlı uygulamaların çoğu en azından aciliyetli olarak kullanım gereksinimi duymayacak. Yani zorunlu bir güncelleme ya da kullanım zorunluluğu duyulmayacak.

Ama uygulamasını ihtiyaçlarına göre, kütüphanenin gücünü de arkasına alarak daha güçlü hale getirmek isteyen herkes için önemli bir özellik. Sonuç olarak state yönetimini asenkron hale getirmek için müthiş bir yenilik. Özellikle içerisinde sayfa sayısı ve işlem seti çok geniş olan kurumsal uygulamalar için oldukça verimli bir yaklaşım olması muhtemel.

Kütüphanenin oldukça “advanced” olan bu yeni özelliğinin, tamamen Facebook’un ihtiyaçları dolayısıyla geliştirildiğini de belirtmek lazım. Bu özelliğin komünite ile paylaşılması da oldukça sevindirici.

Özetlemek Gerekirse

React Concurrent Mode, artık eş zamanlı olarak birden fazla state güncellenmesine olanak tanıyor.

Concurrency;

şeklinde yorumlanabilir.

Henüz herhangi bir React versiyonunda yer almayan bu yeni özelliğin, hangi versiyonla birlikte kullanılmaya başlanacağı tarihle ilgili bilgi de paylaşılmadı. Bu nedenle nihai bir sonuç olmadığı için, önümüzdeki süre zarfında altyapısında ve bazı yaklaşımlarında değişiklikler olması da muhtemel.

Kaynaklar:

Author: Efecan Tekin