Přeskočit na hlavní obsah

React a Typescript podruhé - proklaté this

V předchozím článku jsem ukázal jak používat Typescript v Reactu. Dneska se pojďme podívat na zbylou část, která se bude motat kolem klíčového slova this.

Javascript a this

Spoléhání na this v javascriptu, je stejné, jako hrát ruskou ruletu. Do funkce lze totiž ono this podstrčit a tím změnit kontext. Do toho se ještě zamíchá function.bind, use strict a arrow functions a už z toho máme slušný guláš.

Dnešní článek se bude snažit vám odhalit, jak to s tím samotným this vlastně je a proč je v JSX bind(this) tou nejhorší možnou volbou.

Funkce a this

Lepší, než tisíc slov, je vždy malá ukázka. Pokud máme následující kód, zkuste uhádnout, co bude jeho výsledkem:
function test() {
    return this;
}
console.log(test());

Pokud tento příklad spustíte ve webu, bude dané this obsahovat globální objekt window. Pokud daný kód spustíte v node.js, bude obsahovat globální objekt global. O tom, co je globální objekt, se můžete dočíst zde.

Nyní pojďme náš kód trochu upravit:
function test() {
    'use strict';
    return this;
}
console.log(test());

V současné chvíli bude this undefined. Proč tomu tak je? Důvodem je přidání strict módu. Zjednodušeně se dá říci, že strict mód nám modifikuje chování javascriptu. Tento strict mod vznikl v ES5 a pokud vás zajímá, co všechno modifikuje, můžete si danou věc pročíst zde.

Pojďme si ukázat další variantu:
function test() {
    return this;
}
console.log(test.bind({invasion:'Hello'})());

Výsledkem bude, že this bude obsahovat podstrčený objekt {invasion: 'Hello'}. Toto je přesně ta ukázka, kterou ve svém projektu nechceme používat, ač je to častý jev. Důvod proč, rozeberu v následující ukázce:
import * as React from 'react';

interface Props {
    onClick: (origin: string) => void;
}

export class Button extends React.Component<Props, void> {

    handleOnClick() {
        this.props.onClick('From button component');
    }
    
    render() {
        return (
            <button onClick={this.handleOnClick.bind(this)}>Click me!</button>
        )
    }
}

Co zde vidíme? Máme komponentu s názvem Button, která vrací callback s názvem onClick. Pokud bychom v JSX nepoužili this.handleOnClick.bind(this), tak by naše funkce nemohla použít this.props.onClick(origin). Jak jsme si ukázali výše, tak this je ve funkci buď globální objekt, nebo undefined. Podle toho, zda jsme v režimu strict či nikoli.
Ono by na tomto příkladě nic tak špatného nebylo, až na to, že pokud si uvědomíme, jak funguje React a metoda render, tak zjistíme, že jsme napsali dost neefektivní kód. Metoda render se totiž bude vykonávat velice často a to vždy, když je komponenta poprvé renderována a také ve chvíli, kdy jí předek změní props či se modifikuje state. To od Reactu přeci očekáváme, že takto bude fungovat. Nicméně v případě metody bind se dostáváme k tomu, že vlastně znovu a znovu a znovu vytváříme další funkci. Finále je, že jen dost zatěžujeme Garbage Collector, který musí znovu a znovu zahazovat něco, co jsme vytvořili, aniž bychom o tom věděli.

Jak z toho ven?

První variantou je to, že bind aplikujeme v konstruktoru. Je to efektivní způsob, jak se vyhnout tomu, aby nám nevznikalo příliš funkcí, ale také to je způsob, který bych označil spíše za nedoporučovaný. Důvod proč, je zřejmý. V případě nové handler funkce musíte provést její registraci v konstruktoru.

Pojďme se podívat na ukázku:
import * as React from 'react';

interface Props {
    onClick: (origin: string) => void;
}

export class Button extends React.Component<Props, void> {

    constructor(props: Props, context: any) {
        super(props, context);
        this.handleOnClick = this.handleOnClick.bind(this)
    }

    handleOnClick() {
        this.props.onClick('From button component');
    }

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

Paráda. Sice jsme se zbavili bind v JSX, ale že by to byla taková výhra se říct nedá.

Druhou a lepší variantou jsou arrow functions. Než se dostaneme k výslednému řešení, pojďme se podívat jak to je s this v arrow functions.

Arrow functions a this

Arrow functions byly přidány v ES6 a dá se říci, že díky nim se nám více přiblížilo funkcionální programování. Arrow functions zjednodušují zápis a také mají jednu důležitou vlastnost a tou je právě zmíněné this.

Pojďme se podívat na ukázku:
const test = () => this;
console.log(test());

Skvěle. Máme stejnou funkci test, akorát přepsanou pomocí arrow function. Co bude jejím výsledkem? Bude to prázdný objekt {}. Skvělé na zamotání hlavy :)

Arrow functions mají v this současný kontext. Abychom to lépe pochopili, pojďme se podívat ještě na jednu ukázku:
this.user = {
    id: 1,
    firstName: 'Ales',
    lastName: 'Dostal',
};
const test = () => this;
console.log(test());

Výsledkem bude, že this obsahuje objekt s atributem user.

Nyní si pojďme tuto znalost aplikovat na React komponentu user.

Výsledkem bude následující kód:
import * as React from 'react';

interface Props {
    onClick: (origin: string) => void;
}

export class Button extends React.Component<Props, void> {

    handleOnClick = () => {
        this.props.onClick('From button component');
    };

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

Díky arrow functions již nepotřebujeme ani konstruktor, ani funkci bind.

Závěr

O this v javascriptu je napsáno spoustu článků. Existují i nové návrhy, které by mohly více přispět tomu, abychom se samotnému bind vyhnuli. Asi nejblíže tomu je samotný návrh pomocí dokorátoru @autobind, což jsou v podstatě metadata nad funkcemi, které určují, jak se budou v daném kontextu chovat. Jestli budou dekorátory, které se v nové ECMA specifikaci připravují, tou správnou volbou, to ukáže čas.

Komentáře

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,…