Toto se může stát každému z nás. To si takhle v týmu děláte reduxovou aplikaci, která pomalu roste, jak se blíží termíny. Jednou vstanete, přijdete do práce, zapnete aplikaci a zjistíte, že se ten formulář “tak nějak seká”. Ale formulář o 3 políčcích by přece ani zdaleka neměl mít nějaké výkonnostní problémy, i když to tam někdo zesloní (zkoní, akorát tisíckrát hůře), že?

Světem protřelý vývojář si hned vzpomene, že využije nový postup pro testování výkonu v React 16, aby se podíval, co se děje. Otevře Chrome Devtools, spustí profiling, napíše pár rychlých písmen do formuláře a toto na něj vykoukne:

redux1

Proč se překreslují všechny ty věci, když reálně by se měla překreslovat maximálně červeně orámovaná část, kde sídlí onen inkriminovaný formulář? (Ještě lépe samozřejmě, kdyby se překreslovalo jen dané políčko). Funkce connect (react-redux) přece implementuje shouldComponentUpdate tak, aby se nepřekreslovaly věci, kterým se nemění data ze selectorů. Rychlým review našich mapStateToProps funkcí jsem objevil na první pohled nenápadný problém na více místech aplikace – vytváření nové reference v mapStateToProps! Komponenta s takhle napsaným mapStateToProps se překreslí při jakékoliv akci kdekoliv v aplikaci, i když se jí reálně nezmění žádné vstupy (hodnoty selektorů).


const mapStateToProps = (state) => ({
    project: getProject(state),
    msg: {       
        project: i18n.getMessage(state, "common.project"),        
        warning: i18n.getMessage(state, "common.warning"),
    },
});

Po menší opravě použitím knihovny reselect vypadal další výkonnostní test mnohem příjemněji. Překreslovalo se jen to, co se opravdu překreslovat mělo, a nic víc. (yay!)


const mapMsgToProps = createStructuredSelector({
   project: i18n.getMessage(state, "common.project"),        
   warning: i18n.getMessage(state, "common.warning"),
});
 
const mapStateToProps = (state) => ({
    project: getProject(state),
    msg: mapMsgToProps(state),
});

redux2

Jaké si z tohoto příběhu odnést ponaučení? Nevyplatí se zapomenout, že mapStateToProps se mají vracet buď primitivní hodnoty nebo reference, které se mění, až když se reálně mění hodnota (lze docílít např. pomocí knihoven reselect a immutable.js). A na jakékoli vytváření nových referencí v mapStateToProps si dát při Code Review sakra pozor.