Přeskočit na hlavní obsah

Co mi vadí na React Relay?

Facebook, jakožto technologická firma, je v současné době na vrcholu. Nejenom proto, že dal světu takové věci jako je React či GraphQL, ale také pro to, že jsou to knihovny, které sám Facebook používá. Díky tomu dostanete věc, která je odladěná pro danou činnost a nemusíte se bát, že jí Facebook přestane podporovat. To je asi jeden z největších rozdílů, kterým se vyznačuje Facebook oproti Googlu. Google se v minulosti dost často ukázal jako vrah svých nenarozených dětí. Každý, kdo se kdy setkal s technologiemi jako je Dart, Angular 1 či třeba GWT by mi jistě dal za pravdu.

Nicméně, bylo by příliš krátozraké, kdyby se člověk automaticky adaptoval na to, co Facebook vypustí. Jednou z věcí, přes kterou jsem se nebyl schopen dostat, je Relay.

Dnešní článek bude opačný. Místo, abych se snažil evangelizovat danou technologii, zkusím vysvětlit, proč není Relay zrovna ideální knihovna.

Začněme hezky od začátku.

Co je Relay?


V případě, že začnete používat React a současně GraphQL, dostanete se do fáze, kdy zjistíte, že přesně pro tento "stack" je určen Relay. Zjednodušeně se dá říct, že Relay je abstraktní vrstva nad vašimi React komponentami, která zajišťuje komunikaci s GraphQL serverem a vaší view vrstvou. Odstíní vás od takových věcí jako je samotný "fetch" na server API či nastavování storage, do kterého se budou načtená data ukládat. Dále za Vás bude řešit error handling a vaše komponenty se stanou prezentační vrstvou pro grafové objekty z API. Umí zařídit optimistické mutace, kdy sami říkáte, že server změnu udělá a vy klienta obelstíte tím, že se budete tvářit, jako kdyby k tomu již došlo.

Relay za vás zařídí většinu nudných věcí. To je skvělé. Až na to, že....

Abych byl schopen popsat, co přesně mi vadí, zkusím Relay rozdělit na dvě části, kterých se to týká. Těmi částmi je GraphQL server a React klient.

GraphQL Server


V případě, že se adaptujete na Relay, dostanete studenou sprchu hned na začátku. Zjistíte totiž, že si nemůžete své GraphQL API psát tak, jak se Vám zlíbí. Relay vám bude hodně věcí předepisovat. První z věcí, kterou musíte doplnit je to, že celé query musí být obaleno jedním hlavním query, který v podstatě říká, že se dotazuji na data přihlášeného uživatele. V tom by až takový problém nebyl. Obalíme query jedním root query a je hotovo. Bohužel tomu tak není.

Další věcí, kterou musíte splnit je identifikátor jednotlivých GraphQL objektů. Jinými slovy to znamená, že identifikátor, nebo chcete-li ID musí být unikátní v globálním stavu.

Co to vlastně znamená? 


Představte si situaci, že máte objekt uživatele, který je reprezentován z databáze. V databázi má vlastní ID. Abychom zařídili globální unikátnost, používá se k tomu následující způsob: "K ID uživatele přičtu název GraphQL objektu a vytvořím unikátní hash." V případě zpětného volání dojde k tomu, že GraphQL nejdříve "rozparsuje" daný identifikátor, abychom z něj dostali ID uživatele. Toto celé se děje z prostého důvodu. Relay má na klientovi vlastní storage, ve kterém jsou jednotlivé záznamy uloženy právě s tímto globálním identifikátorem. V případě, že někde dojde ke změne, tak jí propíše všude, kde je daný identifikátor roven.

Opět uvedu příklad.
Mám tabulku online uživatelů, kde je jméno a příjmení. V jiném panelu edituji uživatele, u kterého změním jméno. V případě, že se jedná o záznam, který je použit i v oné tabulce, provede přepis i tam. Tím Relay částečně zajišťuje aktuálnost dat.

Další věcí, kterou musíte splnit jsou kolekce dat. V případě, že používáte pole záznamů (což jistě používáte), musíte tuto kolekci implementovat tak, jak vám předepisuje Relay. Jedná se zejména o stránkování mezi daty.

Poslední věcí, kterou musíte na serveru splnit jsou mutace. Respektive argumenty mutace. Nelze si je napsat jen tak, jak se mi zlíbí. Musí být obaleny přes vlastní GraphQL objekt "input".

Dobrá zpráva je, že pro všechny potřebné změny, pokytuje Relay vlastní knihovny, které v GraphQL objektech buď implementujete, nebo své objekty touto knihovnou obalujete.

Výsledkem je, že vaše GraphQL API bude připravené pro Relay, ale za jakou cenu? Nejen to, že musíte splnit dané podmínky, pro správné fungovaní Relay, ale také nemáte moc možnost z tohoto "uhnout" vlastním směrem.

Relay v tomto případě prohrává 1:0. Je příliš invazivní a příliš me svazuje.

GraphQL Client alias Relay


Nyní se přesuneme směrem ke klientovi.

Po tom, co s potem ve tváři, splníte všechna předepsaná kritéria na straně serveru, tak musíte počítat s tím, že klient na tom není o moc lépe.
Za prvé je nutné celou vaší React aplikaci obalit Relay komponentou, která je obsahuje vlastní store a zařizuje to, aby vám správně fungovalo "injectování" GraphQL dotazů do komponent.
Výsledek je poté následující. Napíšete vlastní komponentu a obalíte jí pomocí Relay, kam zapíšete GraphQL dotaz. Relay poté zařídí, že vaše komponenta dostane výsledná data pomocí "props".

Díky tomu Relay v podstatě nahrazuje nejznámější implemenaci Fluxu a tím je Redux. Pokud byste se totiž rozhodli, že budete chtít používat Relay a k tomu Redux, musím vás zklamat. Tyto dvě technologie jdou částečně proti sobě. Máte Relay a ten vám přeci stačí.

V tom vidím největší nevýhodu na straně klienta. Nejen, že mě nutí používat Relay a zahodit Redux, ale je navíc opět dost invazivní a dost mě uzamyká někde, kde nechci být. Chci mít volnost v tom, jakým způsobem si budu vlastní komponenty navrhovat. Chci si je rozdělit na kontejnery a komponenty. V případě Relay toto neexistuje. Komponenta je totiž často zároveň kontejnerem.

Pro mě Relay na klientu prohrává opět 1:0.

Co s tím?


Pokud se rozhodnete, stejně jako já, že Relay není tou technologií, kterou byste chtěli použít, nabízí se co s tím. Vedle knihovny Relay existuje ještě jedna knihovna a tou je Apollo.

Apollo má výhodu zejména v tom, že je méně invazivní. Nejenom, že vám nabízí, abyste vedle Apolla používali i Redux, ale je i inkrementálně adaptivní. Tedy máte možnost Apollo začít používat i na existujícím projektu, aniž byste museli provést větší refactoring.

Druhou variantou je vlastní řešení.

Vlastní řešení spočívá v jednoduché myšlence. Mám Redux a akce, které ručně vykonávájí načtení dat ze serveru, stejně jako v případě třeba REST API. Prostě si dotazy píšete mimo komponenty a řídíte si sami, co do Reduxu a jak uložíte.

Touto cestou jsem se vydal i já.

Nejenom, že jsem dostatečně flexibilní, ale také jde o to, že samotné dotazy na server jsou velice jednoduché.

Výsledný kód vypadá třeba následovně:

const fetchEdit = (id: string) => {
    return (dispatch: Dispatch<Store>, getState: () => Store) => {
        dispatch({type: LabelActions.FETCHING_LABEL_EDIT});
        const query = `
            query ($id: ID!) {
                label(id: $id) {
                    id
                    name
                    typeId: type {
                        value:id
                        label:key
                    }
                }
            }`;
        client(dispatch, getState)(query, {id}).then((result) => {
            dispatch({type: LabelActions.FETCHED_LABEL_EDIT, payload: result.data.label});
        }).catch((err) => {
            dispatch({type: LabelActions.ERROR_FETCHED_LABEL_EDIT});
            dispatch(MessageActions.setErrorServer(Lang.CONNECTION_ERROR_LABELS_EDIT, err));
        });
    };
};

Metoda načítá data pro editaci:
  1. Nejprve si do reduxu uložím informaci o tom, že dochází k načítání
  2. Poté, co se načtou data, uložím je do reduxu a oznámím, že jsou načtena
  3. V připadě chyby si sám opět zařídím, abych to oznámil do reduxu

Závěr


I přes to, že se dají nalézt výhody, proč se na Relay adaptovat, tak existuje i spoustu důvodů, proč ne. Jedním z hlavních důvodu je to, že pokud se pokusíte použít Relay, bude technologie víc cílem, než cestou. Doufejme, že nová verze, na které se pracuje, bude méně invazivní a umožní i inkrementální adaptaci. Zatím si nechávám Relay v šuplíku a zůstávám u Reduxu s vlastním řešením, které mi vyhovuje víc.

Komentáře

  1. const fetchEdit = (id: string) => {
    return (dispatch: Dispatch, getState: () => Store) => {
    dispatch({type: LabelActions.FETCHING_LABEL_EDIT});

    A přesně tato sémantika (nebo syntaxe, nebo jak bych to napsal) mi na javascriptu vadí. Ve zkratce: jeho kód se mi zdá nečitelný :) Asi jako perl oneliners, jako je tohle:

    perl -lne '(1x$_) !~ /^1?$|^(11+?)\1+$/ && print "$_ is prime"'

    OdpovědětVymazat
    Odpovědi
    1. To je spíše jen o zkušenostech s danou syntaxí a funkcionálním programováním. Kód v podstatě říká: "Mám funkci fetchEdit, která vrací funkci, která ma parametr dispatch, což je také funkce a parametr getState, což je také funkce". Zní to šíleně, vypadá to možná šíleně, ale je to efektivní. Navíc, adaptace není tak těžká. Jen to to chce více myslet v lambda výrazech.

      Vymazat

Okomentovat

Populární příspěvky z tohoto blogu

Jak si v IT vydělat hodně peněz?

Na začátek by bylo dobré, abych objasnil samotný titulek, který může na někoho působit jako červený hadr. Článek nebude o obecných pravidlech, ale bude vyprávět můj vlastní příběh, na kterém vám zkusím ukázat, jak se dá docílit úspěchu, či alespoň správně nastartovat svojí vlastní kariéru v IT.

I když se z názvu článku dá dedukovat, že se vše bude točit kolem peněz, není tomu tak. Alespoň ze dvou třetin určitě ne. Ale to už předbíhám, pojďme to raději vzít hezky popořadě...

Kdybychom měli mluvit o roce 2017 jako o přelomové době, nejspíše to nebude pravda. I když pro někoho to může být rok plný úspěchů a štěstí v podobě narození zdravých dětí, svatby či první velké lásky, tak z pohledu lidstva se jedná o rok, který jen kopíruje předešlé a v oblasti technologií nás posouvá stejným tempem jako rok předtím.

Jsem naprosto přesvědčen o tom, že i když se současná doba tak nenazývá, tak prožíváme dobu, která jednou bude označena za revoluční, a to zejména díky vynálezu internetu, který je s…

Jak by se firmy neměly chovat k programátorům?

Každý, kdo pracuje v IT oboru, se jistě již setkal s různými „geniálními nápady“, od kterých si firma slibovala zlepšení produktivity či snížení nákladů. Ať už je to zavedení agilních principů, striktní kontrola práce či zavedení nové a skvělé metodiky, o které si „šéf“ přečetl včera na internetu. Jsou z toho skutečně tak nadšení i samotní vývojáři? A bude nový nápad fungovat?
K napsání tohoto článku mě navedly různé programátorské diskuze, kde si lidé stěžovali na firmu, kde pracují. Příklady, které zde uvedu, jsou z reálné praxe. Ať už jsem je zažil jako řadový programátor, či jako šéf týmu.
I když je poptávka po programátorech tak vysoká, že Vás headhunteři nahánějí i ve chvílích, kdy o to opravdu nestojíte, tak i přes to je mnoho lidí, kteří se bojí opustit svoje současné zaměstnání.
Čeho se nejčastěji bojíme? Je to samozřejmě nejistota, kterou si často omlouváme větami jako: „Tady mám své pohodlí, co když to jinde mít nebudu?“ nebo „I když mě to v práci štve a nebaví, tak mě ale…

Jak jsem technologicky postavil startup

Tento příběh pojednává o technologiích, nástrojích a vůbec o všem, co jsem potřeboval k tomu, abych byl schopen, postavit startup na zelené louce.

Každý správný příběh začíná stejně: "Jednou jsem...."

Kapitola první: Nápad
Jednou jsem se setkal s člověkem, který měl nápad na produkt, který se v průmyslu zatím nevyskytuje. I přes prvotní skepsi, kdy jsem si říkal: "Tohle už přeci dávno v průmyslu existuje, ne?", jsem došel ke zjištění, že nikoli.

Tím jsem se dostal ke svému prvnímu poučení. Průmysl je technologicky dost zabržděný. Osobně se domnívám, že těch důvodů, proč tomu tak je, je několik. Za prvé je to fakt, že většina lidí, kteří se pohybují v tomto odvětví jsou často konzervativní a za správné považují pouze léty osvědčené věci. Druhým důvodem je to, že jakákoli změna znamená riziko. Ať už z pohledu finanční ztráty tak i z pohledu stability výroby. No a třetím a nejzásadnějším důvodem je to, že ač zde máme spousty technologických vymožeností, narážíme na to,…