Nieco spóźniony, ale dostarczony - 9-ty learning log! Dlaczego z takim opóźnieniem? Odpowiedź jest prosta! Na początku tygodnia przyszedł na świat mój synek...moje pierwsze dziecko :) - Więcej już chyba pisać nie muszę :) Są w życiu rzeczy ważne i ważniejsze. Pomiędzy zmianą pieluszki i kołysaniem do snu znalazłem trochę czasu na opowiedzenie Wam co działo się przez ostatni tydzień w moim programistycznym życiu. Zaczynamy!

Wtopa z eslint

Na pewno słyszeliście newsa - konto jednego z kontybutorów do pakietu eslint zostało zhackowane. Podczas instalacji zaifekowanego pakietu, na komputer użytkownika zaciągany był kod z pastebin.com, który wyciągał dane z pliku .npmrc. Plik ten najczęściej zawiera tokeny autoryzacyjne, dzięki którym atakujący mógł podmieniać następne pakiety. Zainfekowane wersje eslinta zostały wycofane z npm'a, kod na pastebin.com został zdjęty, a npm cofnął autoryzację dla wszystkich tokenów wygenerowanych przed 2018-07-12 12:30 UTC.

We, the ESLint team, are sorry for allowing this to happen. We hope that other package maintainers can learn from our mistakes and improve the security of the whole npm ecosystem.

Na Twiterze pojawiły się apele do twórców, aby włączyć 2FA (two factor authentication).

Znów powrócił temat security w całym ekosystemie npm'a. Zdajecie sobie sprawę, że taki niepozorny linter ma dostęp nie tylko do projektu, w którym go odpalacie. Jeśli zainstalowaliście go globalnie i nie daj boże wykonujecie komendę z sudo (bo inaczej system "coś mi krzyczy") 🤦‍♂️to sami prosicie się o kłopoty ;) NIGDY z sudo! Node.js w przeciwieństwie do przeglądarki nie odpala się w sandboxie. Pamiętajcie o tym.

Postmortem znajdziecie na stronie eslinta.

Render-prop pattern

W 3-cim odcinku LL pisałem o świetnym kursie Kent'a C. Dodds'a na temat wzorców w Reacie. Przy okazji implementacji jednego z komponentów postanowiłem wykorzystać wzorzec render-prop.

Tworząc komponent w React'cie, wszystko co zamieścicie między znacznikami komponentu trafia do pola children.

const Component = ({ children }) => (
  <div>
    { children }
  </div>
);

const Wrapper = () => (
   <Component>
    <a>Link</a> // ten link trafi do pola children
   </Component>
);

Tak wygląda nasze pole children: {$$typeof: Symbol(react.element), type: "a", key: null, ref: null, props: {…},...}

Wzorzec render-prop polega na przekazaniu do "wnętrza" komponentu funkcji. Tak! Funkcji zamiast innych komponentów. Co nam to daje? Dzięki temu nasz komponent jest bardziej kofigurowalny pod kątem tego co będzie wyświetlał.

Załóżmy, że implementujemy drzewko folderów. Każdy folder traktujemy jako węzeł Node. Na początku potrzebujemy proste drzewko do wyświetlania folderów:

Screen-Shot-2018-07-17-at-13.37.43

Nasz komponent mógłby wyglądać tak:

import React, { Component } from "react";

class Node extends Component {

  render(){
    return (
      <div className={ this.props.isSelected ? "folder--selected" : "" }>
        <ArrowStatus isExpanded={ this.props.isExpanded }/>
        <FolderIcon />
        <FolderName>{ this.props.name }</FolderName>
      </div>
    );
  }

}

Przychodzi nowe wymaganie: w jednym z drzewek musimy dodać możliwość zaznaczania poprzez checkbox. Nie chcemy też podświetlać aktywnego folderu. Wyglądać ma to mniej więcej tak:

Screen-Shot-2018-07-17-at-13.37.18

W projektach, w jakich brałem udział, często w takim przypadku rozszerzało się komponent docelowy o swego rodzaju "konfigurację":

import React, { Component } from "react";

class Node extends Component {

  render() {
    const className = this.props.isSelectable && this.props.isSelected
      ? "folder--selected"
      : "";
      
    
    return (
      <div className={ className }>
        <ArrowStatus isExpanded={ this.state.isExpanded }/>
        { this.props.showCheckbox && <Checkbox state={ this.state.checkbox } /> }
        <FolderIcon />
        <FolderName>{ this.props.name }</FolderName>
      </div>
    );
  }

}

To bardzo uproszczona wersja. Brakuje tu implementacji samego zaznaczania, rozwijania itp. Ale widzicie, że z każdym kolejnym wymaganiem będą nam dochodzić konstrukcje typu: isCośTam && pokażCośTam, albo isCośTamInnego ? "taka-specjalna-klasa" : "klasa-niespecjalna" ;)

Z pomocą przychodzi render-prop pattern. Wystarczy, że do tworzonego węzła przekażemy funkcję, która jako argumenty otrzyma interesujące nas elementy ze stanu, oraz funkcje pomocnicze.

import React, { Component } from "react";

class Node extends Component {

  toggle = () => {}

  render() {
    return (
      <div className="folder">
        { this.props.children({ 
            ...this.state,  // stan węzła
            toggle, // funckcja pomocnicza
          }) 
        }
      </div>
    );
  }
}

// Wykorzystanie naszego komponentu:

const Tree = () => (
  <div>
    <Node>
     { ({ isExpanded, toggle }) => (
       <div className="my-custom-class">
         <ArrowStatus isExpanded={ isExpanded } onClick={ toggle }/>
         <FolderName ... />
         <Checkbox ... />
       </div>
     )}
    </Node>
  </div>
)

Przy takiej implementacji nasz komponent Node "martwi" się o całą logikę biznesową, natomiast to, jak będzie wyglądał - definiujemy poprzez funkcję przekazaną jako children. W przykładzie powyżej zamieniłem np. kolejność wyświetlania checkboxa (za nazwą folderu). Wzorzec render-prop sprawia, że wygląd naszego komponentu jest bardziej konfigurowalny.


To tyle...Resztę czasu spędziłem i zamierzam spędzić z rodziną ;) Oznacza to, że najprawdopodobniej przez najbliższe 2 tygodnie nie będzie learning loga. Ale zobaczymy... W sobotę prowadzę swoje pierwsze zajęcia w ramach współpracy z Coders Lab. Trzymajcie kciuki! Na pewno opiszę swoje przemyślenia na temat tego "jak to jest być wykładowcą" ;)

Pozdrawiam i miłego tygodnia!