Jekyll2020-03-10T19:31:11+00:00https://www.nafrontendzie.pl/feed.xmlNa FrontendzieStrona główna bloga Na Frontendzie. Jest to miejsce dla wszystkich front-end developerów. Zarówno Junior jak i Senior znajdzie tutaj coś dla siebie!
3 nawyki wspierające rozwój programisty2020-03-10T18:30:00+00:002020-03-10T18:30:00+00:00https://www.nafrontendzie.pl/3-nawyki-wspierajace-rozwoj-programisty<p>Ostatnio sporo się zmieniło w moim życiu… Staram się jednak obrócić te zmiany na swoją korzyść. W tym celu postanowiłem wprowadzić do swojej codzienności kilka nawyków, które pomogą mi w samo-rozwoju. Kilka z nich dotyczy oczywiście mojego rozwoju jako programista, myślę więc, że część z czytelników bloga może być nimi zainteresowana.</p>
<h2 id="minimum-jeden-techniczny-artykuł-dziennie">Minimum jeden techniczny artykuł dziennie</h2>
<p>Odkąd pamiętam zawsze miałem z tym problem. Pomimo tego, że w sieci znaleźć można setki tysięcy wysokiej jakości technicznych tekstów na temat nowości w naszej branży, itp., nigdy nie byłem w stanie zmusić się do regularnego ich czytania… I to nie tak, że zupełnie olewałem temat. Nie raz i nie dwa, kończyłem dzień/tydzień z kilkoma jak nie kilkunastoma artykułami pootwieranymi w zakładkach przeglądarki. Część z nich jedynie “napoczęta”, reszta nie ruszona… A przecież jeśli chcemy być naprawdę dobrymi programistkami/programistami, powinniśmy rozwijać się cały czas, trzymać rękę na pulsie jeśli chodzi o nowinki programistyczne.</p>
<p>Jednym ze sposobów na zmianę tego stanu rzeczy było, między innymi, powstanie tego bloga. Konieczność dogłębnego zbadania tematu, który chciałem przedstawić na blogu zmuszała mnie do czytania sporej ilości technicznych artykułów. To na pewno podniosło moje programistyczne umięjętności, dlatego wydaje mi się, że wprowadzenie nawyku czytania technicznych artykułów jest <strong>bardzo dobrym pomysłem</strong>!</p>
<p>Jeśli chodzi o źródła z których korzystam, to po pierwsze, wykupiłem subskrypcję na <a href="https://medium.com">medium.com</a> - koszt to $5 miesięcznie (lub $50 rocznie). Dlaczego akurat medium? W dzisiejszych czasach RSS’y odeszły już trochę w zapomnienie, a serwis ten skupia dużą ilość “programistycznych gwiazd”, których publikacje można śledzić w jednym miejscu. Wydaje mi się więc, że w ten dość prosty sposób jestem w stanie każdego dnia znaleźć dla siebie coś interesującego do przeczytania, nie poświęcając specjalnie dużo czasu na wyszukiwanie (kogo dokładnie tam śledzę to temat na osobny wpis).</p>
<p>Drugim źródłem, które ostatnio podsunęli mi inni front-end developerzy z <a href="https://appunite.com">AppUnite</a> (firma, w której obecnie pracuję) to newsletter <a href="https://justjavascript.com">JustJavaScript</a>. Jest to lista mailingowa stworzona przez, nie kogo innego, tylko Dana Abramov’a, który w ten sposób postanowił podzielić się ze społecznością swoim kursem on-line na temat JavaScriptu. Póki co, jest to darmowy content, który z czasem stanie się płatny. Mimo tego, że z JavaScriptem pracuję od lat, to muszę przyznać, że jest to dobry sposób żeby pewne rzeczy sobie przypomnieć, inne poukładać w głowie, a jeszcze inne odkryć. <strong>Polecam</strong>.</p>
<h2 id="rozwiązanie-minimum-jednego-kata-na-codewars-dziennie">Rozwiązanie minimum jednego “kata” na CodeWars dziennie</h2>
<p>Kolejna rzecz, którą “sprzedali” mi koledzy z firmy… Nie wiem czy słyszałaś/słyszałeś o <a href="https://www.codewars.com">CodeWars</a>? Jest to serwis, w którym zgromadzono setki (tysiące?) zadań algorytmicznych, które można rozwiązywać w wielu różnych językach programowania (oczywiście JavaScript oraz TypeScript są obecne). Zadania mają różny poziom, po rozwiązaniu mamy dostęp do rozwiązań innych użytkowników, możemy też oceniać i komentować ich solucje. Za rozwiązane zadania dostajemy też punkty w rankingu, które zwiększają nasz poziom wtajemniczenia (im wyższy poziom, tym trudniejsze są zadania).</p>
<p>Muszę powiedzieć, że jestem zachwycony tym serwisem - zadania zacząłem rozwiązywać jakiś tydzień temu i chyba jestem już uzależniony… Nie wiem czy to dzięki wymienionym wyżej elementom “grywalizacji” czy raczej dzięki temu, że póki co całkiem dobrze mi idzie. Jest to dla mnie chyba najłatwiejszy nawyk do wprowadzenia. Wydaje mi się również, że może mnie to naprawdę rozwinąć jako programistę - zadania nie są trywialne (szczególnie na wyższych poziomach), a ich algorytmiczny charakter sprawia, że jest to fajna odmiana od tego co robimy na codzień (serwis -> model -> komponenty -> powtórz). <strong>Naprawdę polecam każdemu!</strong></p>
<h2 id="angielski">Angielski…</h2>
<p>Jak wiadomo, każdy programista oprócz szeregu języków programowania, powinien też znać język angielski. Jeśli chodzi o mnie to nigdy nie czułem się w tym obszarze szczególnie pewnie. Byłem w stanie dogadać się z klientem w sprawie wymagań itp., i było to zwykle wystarczające. Zawsze jednak towarzyszył mi przy tym pewien stres i niezadowolenie z siebie, że nie jestem w stanie mówić lepiej.</p>
<p>Na początku roku postawiłem sobie za cel, że w końcu coś z tym zrobię (w sensie osiągnę płynność w posługiwaniu się tym językiem). I tutaj również z pomocą przyszło mi kilka nawyków, które postanowiłem wprowadzić do swojego życia. Myślę, że przy nauce języków obcych wyrobienie sobie nawyków jest kluczowe - to żmudny proces, w którym bardzo ważna jest systematyczność.</p>
<p>Jakie nawyki związane z nauką języka angielskiego wprowadziłem? Oto ich lista:</p>
<ul>
<li>codzienne czytanie po angielsku, najlepiej powieści (czy ogólnie coś co mnie interesuje i czytanie tego będzie przyjemnością), min. 30 minut - nie wliczam tutaj czytania technicznych artykułów mimo, że zwykle też są po angielsku</li>
<li>codzienne oglądanie seriali/youtube po angielsku - jeśli da radę, to staram się to robić bez napisów, jeśli używany jest trudniejszy język, włączam angielskie napisy; tutaj mogę polecić kanał <a href="https://www.youtube.com/channel/UCKgpamMlm872zkGDcBJHYDg">Learn English With TV Series</a> gdzie na czynniki pierwsze rozbijane są sceny z filmów, seriali i teledysków (tutaj podziękowania dla Darii, mojej liderki z AppUnite, która poleciła mi ten kanał)</li>
<li>codzienne powtarzanie nowych słówek metodą SuperMemo (aplikacja sama zarządza tym, kiedy dane słówko powinniśmy powtórzyć aby go nie zapomnieć) - więcej o tej metodzie <a href="https://www.supermemo.com/en">tutaj</a></li>
<li>raz w tygodniu dodawania nowych słówek do SuperMemo - przez cały tydzień, czytając czy oglądając treści po angielsku, notuję nowe słówka, które poznaję; następnie raz w tygodniu dodaję je do aplikacji wspomagającej powtórki (patrz poprzedni punkt)</li>
</ul>
<p>Do tego dorzuciłem konwersacje z native speakerem przez Skype, 3 razy w tygodniu, ale tego nie zaliczam jako nawyk (chociaż podejrzewam, że może to być kluczowe jeśli chodzi o moje postępy). Muszę szczerze przyznać, że to wszystko (robię to od ok 2 miesięcy) w widoczny sposób poprawiło mój angielski - na pewno czuję się już pewnie i swobodnie rozmawiając z klientem. Wciąż czuję braki jeśli chodzi o słownictwo, mam momenty, że nie wiem jak coś ubrać w słowa ale zdarza się to coraz rzadziej. Jeśli uda mi się utrzymać te nawyki przez dłuższy czas to myślę, że dam radę osiągnąć mój cel w tym roku!</p>
<h2 id="jak-wprowadzam-nawyki-w-życie">Jak wprowadzam nawyki w życie?</h2>
<p>Powyżej przedstawiłem 3 nawyki (lub bardziej grupy nawyków), które do tej pory wprowadziłem do swojego życia. Myślę jednak, że część z czytelniczek i czytelników może być zainteresowana w jaki sposób te nawyki “ogarniam”.</p>
<p>Otóż, używam do tego aplikacji o nazwie <a href="http://www.habitbull.com">HabitBull</a>, która jest dostępna zarówno na iPhone jak i na Androida. Jeśli mam pomysł na nawyk, który chciałbym w sobie wyrobić, dodaję go do aplikacji. Codziennie po pracy zaglądam do aplikacji i sprawdzam co tam mam do zrobienia. A jeśli coś z tych zadań wykonam, oznaczam to w apce.</p>
<p>Aplikacja pokazuje w % jak dobrze dotychczas idzie mi wypełnianie danego nawyku. Jeśli, któryś dzień odpuszczę, już nigdy nie zobaczę 100% - mnie to osobiście motywuje…</p>
<h2 id="podsumowanie">Podsumowanie</h2>
<p>To tyle na dziś… W sumie planowałem krótki wpis, a wyszło jak widać. Mam nadzieję, że moje pisanie jeszcze zupełnie nie zardzewiało - w końcu, to pierwsze wpis po ponad roku od ostatniej publikacji. Mam nadzieję, że to nie jest moje ostatnie słowo w tym roku - może pisanie postów też powinno stać się moim nowym nawykiem?</p>bartek-dybowskiOstatnio sporo się zmieniło w moim życiu… Staram się jednak obrócić te zmiany na swoją korzyść. W tym celu postanowiłem wprowadzić do swojej codzienności kilka nawyków, które pomogą mi w samo-rozwoju. Kilka z nich dotyczy oczywiście mojego rozwoju jako programista, myślę więc, że część z czytelników bloga może być nimi zainteresowana.Create React App - generowanie stron statycznych2019-02-18T06:00:00+00:002019-02-18T06:00:00+00:00https://www.nafrontendzie.pl/create-react-app-generowanie-stron-statycznych<p>Inspirację do napisania tego wpisu, jak to często już u mnie bywało, przyniosło samo życie. Jednym z pierwszych projektów w <a href="https://goingapp.pl">Going.</a>, w którym przyszło mi brać udział było stworzenie <strong>statycznej</strong> strony strony www. Mogłem oczywiście napisać wszystko w czystym HTML + CSS + jQuery (sic…). Strona miała jednak zawierać dość dużo logiki biznesowej w JavaScript, do tego routing, a poza tym chodziło również o to, aby rozwiązanie było podstawą do dalszej rozbudowy w przyszłości.</p>
<p>Zdecydowałem więc, że trzeba by to jednak jakoś ogarnąć w React… Idealnie byłoby oprzeć całość na <a href="https://github.com/facebook/create-react-app">Create React App</a> bez “ejectowania” go, tak aby w przyszłości mieć mniej problemów z podbijaniem wersji pakietów. Po krótkim research’u okazało się, że to co chcę osiągnąć (generowanie statycznych podstron na podstawie routingu zdefiniowanego w aplikacji React) jest jak najbardziej możliwe. O szczegółach tego rozwiązania przeczytasz w niniejszym wpisie.</p>
<h2 id="biblioteka-react-snapshot">Biblioteka <code class="highlighter-rouge">react-snapshot</code></h2>
<p>Jak już nie raz i nie dwa się przekonałem, w repozytoriach <a href="https://www.npmjs.com" title="Strona główna npm">npm</a> są rozwiązania <strong>prawie</strong> na wszystkie problemy… Nie inaczej było także w tym przypadku. Okazuje się, że istnieje biblioteka, która robi dokładnie to czego potrzebuję! Mowa tutaj o <a href="https://github.com/geelen/react-snapshot" title="Strona projektu react-snapshot na Githubie">react-snapshot</a>.</p>
<p>Sposób użycia tej biblioteki w aplikacji opartej o Create React App jest banalnie prosty! Oczywiście pierwsza rzecz to instalacja biblioteki w naszym projekcie:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yarn add <span class="nt">--dev</span> react-snapshot
</code></pre></div></div>
<p>Kolejna rzecz to drobna modyfikacja skryptu <code class="highlighter-rouge">npm</code>, służącego do budowania aplikacji (nie potrzebujemy snapshotów w trybie developerskim):</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">"build"</span><span class="p">:</span><span class="w"> </span><span class="s2">"react-scripts build && react-snapshot"</span><span class="w">
</span></code></pre></div></div>
<p>Powyższe, po zakończeniu budowania aplikacji, uruchamia generowanie statycznych stron HTML na podstawie podstron istniejących w routingu naszej strony.</p>
<p>Ostatnia rzecz do zrobienia, to lekka zmiana w pliku <code class="highlighter-rouge">index.js</code>:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// import ReactDOM from 'react-dom';</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">render</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react-snapshot</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">App</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">./App</span><span class="dl">'</span><span class="p">;</span>
<span class="nx">render</span><span class="p">(</span>
<span class="o"><</span><span class="nx">App</span><span class="o">/></span><span class="p">,</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">root</span><span class="dl">'</span><span class="p">)</span>
<span class="p">);</span>
</code></pre></div></div>
<p>Jak widzisz, biblioteka <code class="highlighter-rouge">react-snapshot</code> dostarcza własną wersję metody <code class="highlighter-rouge">render</code>. Aby więc generowanie statycznych podstron działało, wystarczy zaimportować ją i użyć zamiast standardowej metody <code class="highlighter-rouge">render</code>, którą zwykle importujemy z pakietu <code class="highlighter-rouge">react-dom</code>.</p>
<p>I to w zasadzie wszystko. Wystarczy teraz uruchomić polecenie</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yarn build
</code></pre></div></div>
<p>…a po chwili w katalogu <code class="highlighter-rouge">build</code> projektu pojawią się pliki HTML odpowiadające poszczególnym podstronom naszej aplikacji.</p>
<p>W tym miejscu warto zwrócić uwagę, w jaki sposób tworzone są katalogi i pliki w oparciu o routing naszej aplikacji. Np. dla ścieżki <code class="highlighter-rouge">/costam-costam/123</code> utworzony zostanie katalog <code class="highlighter-rouge">costam-costam</code>, a w nim znajdzie się plik HTML o nazwie <code class="highlighter-rouge">123.html</code>. Warto mieć to na uwadze przy konfiguracji serwera.</p>
<h2 id="dodatkowa-konfiguracja">Dodatkowa konfiguracja</h2>
<p>Korzystając z biblioteki <code class="highlighter-rouge">react-snapshot</code> dość szybko możemy natknąć się na pewien problem: struktura drzewa stron naszej aplikacji budowana jest w oparciu o linki dostępne w aplikacji. Jeśli więc do którejś z podstron nie ma w aplikacji odnośnika, <code class="highlighter-rouge">react-snapshot</code> może nie wygenerować dla niej pliku HTML.</p>
<p>Na szczęście można sobie z tym dość łatwo poradzić. Wystarczy do pliku <code class="highlighter-rouge">package.json</code> dodać sekcję <code class="highlighter-rouge">react-snapshot</code>:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">"reactSnapshot"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"include"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="s2">"/not-found"</span><span class="p">,</span><span class="w">
</span><span class="p">],</span><span class="w">
</span><span class="nl">"exclude"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="s2">"/signup"</span><span class="p">,</span><span class="w">
</span><span class="p">],</span><span class="w">
</span><span class="nl">"snapshotDelay"</span><span class="p">:</span><span class="w"> </span><span class="mi">300</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>W powyższym przykładzie informuję bibliotekę <code class="highlighter-rouge">react-snapshot</code> o konieczności odwiedzenia ścieżki <code class="highlighter-rouge">/not-found</code> podczas generowania statycznych stron. Nastąpi to nawet jeśli w aplikacji nie ma ani jednego odnośnika do tej strony.</p>
<p>Oprócz tego, wyłączam z generowania ścieżkę <code class="highlighter-rouge">/signup</code> - może się to przydać jeśli nie chcemy by narzędzie generowało plik HTML dla jakichś obszarów aplikacji.</p>
<p>Standardowo, biblioteka czeka 50ms na wyrenderowanie strony zanim wygeneruje na tej podstawie statyczną stronę. Ostatni parametr, <code class="highlighter-rouge">snapshotDelay</code> pozwala zmienić opóźnienie generowania snapshotów tak by dopasować je do potrzeb naszej aplikacji.</p>
<h2 id="zastosowania-i-podsumowanie">Zastosowania i podsumowanie</h2>
<p>Jak na pewno się domyślasz, tego typu biblioteka nie nadaje się do wszystkiego… Jej podstawowym założeniem jest, że wszystkie dane wyświetlane na stronie są statyczne. <strong>Nie jest więc możliwe</strong> wykorzystanie tej biblioteki w przypadku generowania linków do podstron na podstawie danych pobieranych asynchronicznie z API!</p>
<p>Jest to natomiast świetne rozwiązanie do wszelkiego rodzaju stron typu landing-page, nawet mocno rozbudowanych, zawierających wiele statycznych podstron. W przypadku tego typu aplikacji myślę, że biblioteka <code class="highlighter-rouge">react-snapshot</code> może okazać się przydatna.</p>bartek-dybowskiInspirację do napisania tego wpisu, jak to często już u mnie bywało, przyniosło samo życie. Jednym z pierwszych projektów w Going., w którym przyszło mi brać udział było stworzenie statycznej strony strony www. Mogłem oczywiście napisać wszystko w czystym HTML + CSS + jQuery (sic…). Strona miała jednak zawierać dość dużo logiki biznesowej w JavaScript, do tego routing, a poza tym chodziło również o to, aby rozwiązanie było podstawą do dalszej rozbudowy w przyszłości.4Developers 2019: Rusza kolejna edycja największego Festiwalu Technologicznego w Polsce2019-01-15T14:10:00+00:002019-01-15T14:10:00+00:00https://www.nafrontendzie.pl/4developers-2019-rusza-kolejna-edycja<p><span class="omit-on-homepage">Uwaga - informacja prasowa</span>2000 uczestników i niemal 100 cenionych ekspertów z branży IT w jednym miejscu. Przed nami ogromne, interdyscyplinarne spotkanie polskiej społeczności programistycznej. W ciągu jednego dnia specjaliści i pasjonaci IT będą mogli uczestniczyć w niemal 100 praktycznych prelekcjach. <strong>Już 8 kwietnia 2019 w Warszawie odbędzie się kolejna edycja 4Developers 2019!</strong></p>
<h2 id="interdyscyplinarność-to-domena-festiwalu">Interdyscyplinarność to domena Festiwalu</h2>
<p>4Developers wyróżnia niezmienna od lat formuła - kilkanaście ścieżek zbudowanych wokół wybranych języków programowania. Różne technologie i najświeższe tematy z branży IT w jednym miejscu. Każdej ze ścieżek tematycznych towarzyszy grono ekspertów, którzy dbają o wysoki poziom merytoryczny przedstawianych w agendzie tematów. Na Festiwalu gromadzą się liczni przedstawiciele społeczności programistycznych z całej Polski – to niepowtarzalna okazja, by zawrzeć nowe znajomości i być na bieżąco z trendami ze środowiska IT.</p>
<p>Festiwalowy charakter 4Developers wynika przede wszystkim z otwartej atmosfery, która panuje podczas wydarzenia. Na tej konferencji eksperci chętnie dyskutują z uczestnikami, a prelegenci starają się odpowiadać na najbardziej skomplikowane pytania. Mnóstwo przestrzeni do chilloutu, niezapomniane i bogate w networking Before Party oraz festiwalowe atrakcje sprawiają, że nawiązywanie nowych znajomości staje się niesłychanie proste!</p>
<h2 id="cloud-computing-i-data-science--nowości-w-agendzie">Cloud Computing i Data Science – nowości w agendzie</h2>
<p>Nad wysokim poziomem wykładów, które pojawią się na 4Developers 2019, czuwa <strong>Rada Programowa</strong>, złożona z czołowych polskich ekspertów z branży IT. Każdy ekspert czuwa nad konkretną ścieżką tematyczną. Podczas tegorocznej edycji uczestnicy będą mogli udać się na wykłady i warsztaty w ramach <strong>13 różnych ścieżek</strong>:</p>
<ul>
<li>.NET</li>
<li>Architektury aplikacji</li>
<li>Bottega IT Minds</li>
<li>Bottega Frontend</li>
<li>C++</li>
<li>Cloud Computing</li>
<li>Data science</li>
<li>Java</li>
<li>JavaScript</li>
<li>PHP</li>
<li>Python</li>
<li>Mobile</li>
<li>Soft Skills & business relations</li>
</ul>
<p>W Radzie Programowej 2019 pojawią się:</p>
<ul>
<li>Maciej Aniserowicz</li>
<li>Bartek Glac</li>
<li>Michał Bartyzel</li>
<li>Jakub Wasielak</li>
<li>Tomasz Ducin</li>
<li>Joanna Lamch</li>
<li>Łukasz Łuczak</li>
<li>Mateusz Pusz</li>
<li>Mariusz Gil</li>
<li>Jakub Pilimon</li>
<li>Janusz Kamieński</li>
<li>Sławomir Sobótka</li>
<li>Marcin Szeliga</li>
</ul>
<p>Jakie nowości w tegorocznej agendzie?</p>
<p>Po raz pierwszy na Festiwalu 4Developers pojawią się ścieżki: <strong>Cloud Computing</strong> i <strong>Data Science</strong>. Natomiast swój wielki powrót będzie mieć ścieżka <strong>Mobile</strong>, którą przygotuje <strong>Joanna Lamch</strong>. To wyjątkowa edycja, ponieważ każda z przygotowanych dla Was ścieżek dotyczy odmiennej tematyki!</p>
<h2 id="od-juniora-do-seniora-praktycznawiedza-i-wymiana-doświadczeń">Od juniora do seniora: praktyczna wiedza i wymiana doświadczeń</h2>
<p>Interdyscyplinarność 4Developers to nie tylko szerokie spektrum tematów do wyboru, ale również rozległa skala poziomu zaawansowania. Festiwal odwiedzają profesjonaliści, którzy chętnie wymieniają się doświadczeniami z uczestnikami stawiającymi pierwsze kroki w branży IT. Zarówno jedni, jak i drudzy, znajdą tu tematy dostosowane do ich potrzeb.</p>
<h2 id="trwa-nabór-prelegentów---call-for-papers-już-otwarte">Trwa nabór prelegentów - Call for Papers już otwarte!</h2>
<p>Niewiele wydarzeń daje możliwość wystąpienia przed tak różnorodną, otwartą publicznością. 4Developers jest doskonałym miejscem, by sprawdzić się na dużej scenie. Każdy, kto chce spróbować swoich sił i zaproponować temat, może wysłać swoje zgłoszenie przez formularz Call For Papers, dostępny na stronie Festiwalu: <a href="https://www.4developers.org.pl">www.4developers.org.pl</a>.</p>
<p>Organizatorzy czekają na zgłoszenia propozycji prezentacji do <strong>końca stycznia</strong>.</p>bartek-dybowskiUwaga - informacja prasowa2000 uczestników i niemal 100 cenionych ekspertów z branży IT w jednym miejscu. Przed nami ogromne, interdyscyplinarne spotkanie polskiej społeczności programistycznej. W ciągu jednego dnia specjaliści i pasjonaci IT będą mogli uczestniczyć w niemal 100 praktycznych prelekcjach. Już 8 kwietnia 2019 w Warszawie odbędzie się kolejna edycja 4Developers 2019!Co dalej z blogiem i kursem on-line?2019-01-08T05:00:00+00:002019-01-08T05:00:00+00:00https://www.nafrontendzie.pl/co-dalej-blogiem-kursem-online<p>Halo halo! Witam po raz pierwszy <strong>od września 2018</strong> kiedy to tutaj, na blogu, pojawił się ostatni wpis… Dawni, stali czytelnicy bloga pewnie zastanawiają się co się ze mną dzieje, dlaczego nic się tutaj nowego nie pojawia i czy w ogóle blog jeszcze żyje. Sam się ostatnio nad tym zastanawiałem, a że przyszedł nowy rok (wiadomo… czas podsumowań, co widać choćby w polskiej, programistycznej blogosferze), to postanowiłem zebrać się w sobie i w końcu coś napisać.</p>
<h2 id="co-dalej-z-blogiem">Co dalej z blogiem</h2>
<p>Ogólnie sprawa wygląda tak (nie pamiętam czy o tym już kiedyś wcześniej pisałem): pod koniec 2016 roku, po 10 latach kariery jako programista postanowiłem zwolnić się z pracy i nie zatrudniać się nigdzie indziej. Naprawdę wtedy miałem już dość programowania, pracy dla kogoś itd. Miałem oczywiście na tę okoliczność odłożone oszczędności, które spokojnie miały starczyć na conajmniej pół roku bez pracy (jeśli też myślisz o takim ruchu - <strong>koniecznie się w ten sposób zabezpiecz</strong>!). Nie zamierzałem jednak w tym czasie leżeć do góry brzuchem - plan był taki, że wolny czas poświęcę maksymalnie na rozwój bloga i zobaczę czy to przyniesie jakieś możliwości, żeby się z tego utrzymać…</p>
<p>W tzw. “międzyczasie” postanowiłem też, że zrealizuję kurs on-line, co ostatecznie udało mi się osiągnąć (<a href="https://www.nafrontendzie.pl/przedsprzedaz-kursow-on-line-podsumowanie">tutaj przeczytasz o wynikach przed-sprzedaży kursu</a>, a <a href="https://www.nafrontendzie.pl/podstawy-react">tutaj landing page kursu</a>). Na ten temat na razie nie będę się rozwodzić - więcej napiszę w dalszej części tego posta.</p>
<p>Wracając jednak do bloga - podczas tego około półtorarocznego okresu bycia “na swoim” powstało masę wpisów (głównie na tematy związane React, ale też sporo tekstów skupiających się ogólnie na pracy programisty), dzięki czemu blog <strong>bardzo się rozwinął</strong> i zyskał dużą popularność. Nigdy jednak nie udało mi się go “zmonetyzować” (nie licząc kursu React). Miałem kilka propozycji współprac komercyjnych ale nigdy nie zdecydowałem się na nie, ponieważ nie byłem przekonany, że to jest coś co mogę z czystym sumieniem polecić moim czytelnikom. Z czasem przestało to dla mnie być priorytetem i dziś o blogu myślę bardziej jak o narzędziu do rozwijania marki osobistej.</p>
<p>Poza tym po kilkumiesięcznym okresie odpoczynku od programowania, powoli zaczęło mi tego brakować. Traf chciał, że w tym czasie odezwali się do mnie znajomi, próbujący rozwinąć swój start-up i zapytali czy nie chciałbym robić dla nich front-end. Od razu się zgodziłem dzięki czemu wróciłem do programowania. Praca przy tym projekcie utwierdziła mnie w przekonaniu, że to programowanie jest jednak czymś, czym chcę się nadal zajmować i jeśli mam stworzyć kiedyś coś własnego, to będzie to raczej jakiś produkt, przy którym sam będę, przynajmniej na początku, pracować.</p>
<p>Przy wspomnianym projekcie start-up’owym pracowałem jako freelancer. Niestety po paru miesiącach zaczęły się problemy z płynnością finansową tej firmy (opóźnienia w płatnościach za moje faktury i tego typu problemy). W tamtym czasie wciąż jeszcze dość prężnie blogowałem, chociaż już nie z taką werwą jak na początku - możliwość pisania postów była bardziej odskocznią od problemów związanych z pracą (to nie pierwszy raz kiedy blog spełniał u mnie taką funkcję). Problemy te, oraz konstatacja, że z blogowania tak naprawdę wcale nie chcę się utrzymywać spowodowały, że postanowiłem, <strong>przynajmniej na razie,</strong> wrócić do regularnej pracy jako front-end developer.</p>
<p>Jak pomyślałem tak zrobiłem i tym sposobem od połowy lipca znów pracuję jako front-end developer w warszawskiej firmie <a href="https://goingapp.pl/">Going.</a> (praca oczywiście zdalna). Wszystko to, co napisałem powyżej (rezygnacja z próby utrzymywania się z bloga, problemy z płatnościami w start-upie, dla którego pracowałem) oraz naprawdę ciekawe wyzwania w nowej pracy sprawiły, że blog zszedł na dalszy plan… czego efektem kompletny brak aktywności na blogu.</p>
<p>Nigdy jednak nie pomyślałem żeby zupełnie zrezygnować z pisania! Blogowanie zawsze dawało mi możliwość dzielenia się wiedzą oraz motywację aby poznawać nowe technologie i nowinki ze świata front-endu. Dlatego więc teraz, pół roku po powrocie do pracy, powoli znów zaczynam czuć głód blogowania. Myślę, że w najbliższych miesiącach znów zaczną pojawiać się tutaj nowe wpisy. Tematów trochę mi się nazbierało więc myślę, że tych nie zabraknie. Oczywiście nie będzie to taka częstotliwość publikacji do jakiej w pewnym momencie przyzwyczaiłem czytelników (3 wpisy tygodniowo)… Ale na pewno będzie tego więcej niż ostatnio!</p>
<h2 id="co-dalej-z-kursem-on-line">Co dalej z kursem on-line</h2>
<p>Wspomniany wcześnie kurs on-line z podstaw React był jedyną zakończoną sukcesem próbą “monetyzacji” mojego bloga. Jego stworzenie dało mi, z jednej strony sporo satysfakcji z możliwości podzielenia się swoja wiedzą i jednocześnie zarobienia na tym. Z drugiej jednak strony praca nad nim dała mi w kość… Nie sądziłem, że taki kurs oznacza aż tyle pracy.</p>
<p>Z tego też względu niestety nie poszedłem za ciosem i nie stworzyłem od razu kolejnych kursów, które mógłbym sprzedawać przez bloga. Podejrzewam, że prawdopodobnie w pewnym momencie byłbym w stanie się z takiej działalności utrzymywać… Nie jest jednak powiedziane, że kolejne kursy nigdy nie powstaną. Na pewno chciałbym zrobić w tym temacie coś więcej. Czy to się uda? Czas pokaże.</p>
<p>Na razie jednak muszę skupić się na kursie z podstaw React, który mam w ofercie. Przez ten rok od jego publikacji, trochę się on już zestarzał. Uważam, że przedstawiane w nim zagadnienia nadal są wystarczające do wejścia w świat React, jednak przydałoby się go trochę odświeżyć i uzupełnić o nowości, które pojawiły się od czasu jego publikacji.</p>
<p>Dlatego też postanowiłem, że na jakiś czas zawieszę jego sprzedaż. W tym czasie wprowadzę w nim odpowiednie zmiany i wtedy kurs wróci do sprzedaży. Kiedy dokładnie sprzedaż zostanie zawieszona? <strong>Za niecały tydzień od teraz czyli 13 stycznia 2019 roku o godzinie 20:00!</strong> Jeśli więc wciąż akurat się zastanawiasz nad zakupem mojego kursu - warto się pospieszyć, ponieważ nie wiem kiedy dokładnie zostanie on wznowiony…</p>
<blockquote>
<p>Kiedy dokładnie sprzedaż <a href="https://www.nafrontendzie.pl/podstawy-react">kursu Podstawy React</a> zostanie zawieszona? <strong>Za niecały tydzień od teraz czyli 13 stycznia 2019 roku o godzinie 20:00!</strong></p>
</blockquote>
<p>Oczywiście osoby, które wykupiły już dostęp do kursu, nie mają się czym martwić! Nadal będą mogły z niego korzystać tak jak do tej pory. <strong>Nie stracą one również dostępu do kursu po jego aktualizacji!</strong></p>
<h2 id="podsumowanie">Podsumowanie</h2>
<p>Hmm… Nawet się rozpisałem - nie spodziewałem się tego. Chyba jednak trochę mi brakowało tego pisania. Cieszę się, że opisałem to wszystko co działo się w moim życiu przez ostatnie prawie dwa lata. <strong>Mam nadzieję</strong>, że uda mi się zrealizować ten plan powrotu do blogowania. Myślę, że może to być z korzyścią zarówno dla czytelników jak i dla mnie. A czy to się wszystko uda tak jak bym chciał? Czas pokaże…</p>bartek-dybowskiHalo halo! Witam po raz pierwszy od września 2018 kiedy to tutaj, na blogu, pojawił się ostatni wpis… Dawni, stali czytelnicy bloga pewnie zastanawiają się co się ze mną dzieje, dlaczego nic się tutaj nowego nie pojawia i czy w ogóle blog jeszcze żyje. Sam się ostatnio nad tym zastanawiałem, a że przyszedł nowy rok (wiadomo… czas podsumowań, co widać choćby w polskiej, programistycznej blogosferze), to postanowiłem zebrać się w sobie i w końcu coś napisać.Context API w React!2018-09-05T05:25:00+00:002018-09-05T05:25:00+00:00https://www.nafrontendzie.pl/context-api-react<p>Wraz z pojawieniem się wersji <strong>v16.3.0</strong> Reacta, do naszych rąk trafiła całkiem nowa i myślę, że całkiem przydatna funkcjonalność. Mowa tutaj o tytułowym <strong>Context API</strong>, które pozwala na wprowadzenie do aplikacji pewnych globalnych ustawień, od których zależeć mogą niektóre komponenty. Dzięki temu implementacja w aplikacji, na przykład, wielu wersji kolorystycznych staje się dziecinnie prosta. Zresztą sam się za chwilę o tym przekonasz!</p>
<h2 id="tworzymy-kontekst">Tworzymy kontekst</h2>
<p>Aby przekonać się jak można wykorzystać mechanizm kontekstu w React, stworzymy za chwilę prostą aplikację, w której możliwe będzie <strong>dynamiczne</strong> zmienianie koloru tekstu. Na początku oczywiście należy kontekst utworzyć.</p>
<p>API nowej wersji Reacta wzbogacone zostało o metodę <code class="highlighter-rouge">createContext</code>, której zadaniem jest, jak sama nazwa wskazuje, <strong>tworzenie kontekstu</strong>. Spójrzmy jak możemy z niej skorzystać (ja robię to w osobnym pliku o nazwie <code class="highlighter-rouge">ColorContext.js</code>, ponieważ wartość zwracana przez ten moduł będzie wykorzystywana w kilku miejscach):</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">React</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="k">export</span> <span class="kd">const</span> <span class="nx">ColorContext</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nx">createContext</span><span class="p">(</span><span class="dl">'</span><span class="s1">red</span><span class="dl">'</span><span class="p">);</span>
</code></pre></div></div>
<p>W powyższym przykładzie tworzona i eksportowana jest stała <code class="highlighter-rouge">ColorContext</code>, do której utworzenia posłużyła metoda <code class="highlighter-rouge">createContext</code>. Myślę, że warto wiedzieć, co dokładnie zwracane jest jako wynik działania tej funkcji. Szybki rzut oka na dokumentację, w której widnieje taki przykład:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="p">{</span> <span class="nx">Provider</span><span class="p">,</span> <span class="nx">Consumer</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nx">createContext</span><span class="p">(</span><span class="nx">defaultValue</span><span class="p">);</span>
</code></pre></div></div>
<p>Oznacza to, że obiekt <code class="highlighter-rouge">ColorContext</code>, który utworzyliśmy w naszym przykładzie zawiera <strong>dwie właściwości</strong> (komponenty): <code class="highlighter-rouge">Provider</code> oraz <code class="highlighter-rouge">Consumer</code>. Za chwilę z nich skorzystamy - na razie napiszę jedynie, że komponent <code class="highlighter-rouge">Provider</code> służy do dostarczania kontekstu swoim dzieciom. <code class="highlighter-rouge">Consumer</code> natomiast to komponent umożliwiający odczytanie i wykorzystanie aktualnej wartości kontekstu dostarczanego przez <strong>najbliższy</strong> <code class="highlighter-rouge">Provider</code> (iterując w górę drzewa VirtualDOM).</p>
<p>Drugą istotną rzeczą w naszym przykładzie jest wartość tekstowa <code class="highlighter-rouge">red</code> przekazywana do metody <code class="highlighter-rouge">createContext</code>. Parametr ten jest <strong>wartością domyślną</strong> dla komponentu <code class="highlighter-rouge">Consumer</code>, która zostanie wykorzystana jedynie w przypadku gdy wśród jego rodziców “konsumera” nie zostanie znaleziony żaden <code class="highlighter-rouge">Provider</code>.</p>
<p>Jeśli powyższe nie jest zrozumiałe, nie martw się - za chwilę wszystko się trochę bardziej rozjaśni.</p>
<h2 id="komponent-provider">Komponent <code class="highlighter-rouge">Provider</code></h2>
<p>Jak wspomniałem powyżej, komponent <code class="highlighter-rouge">Provider</code> pozwala na dostarczenie kontekstu do komponentów dzieci. Spójrz na przykład:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">Component</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">ColorContext</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">./ColorContext</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">WelcomeText</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">./WelcomeText</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">class</span> <span class="nx">App</span> <span class="kd">extends</span> <span class="nx">Component</span> <span class="p">{</span>
<span class="nx">state</span> <span class="o">=</span> <span class="p">{</span> <span class="na">color</span><span class="p">:</span> <span class="dl">'</span><span class="s1">red</span><span class="dl">'</span> <span class="p">};</span>
<span class="nx">onColorChange</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">color</span> <span class="p">}</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">newColor</span> <span class="o">=</span> <span class="nx">color</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">red</span><span class="dl">'</span> <span class="p">?</span> <span class="dl">'</span><span class="s1">black</span><span class="dl">'</span> <span class="p">:</span> <span class="dl">'</span><span class="s1">red</span><span class="dl">'</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span> <span class="na">color</span><span class="p">:</span> <span class="nx">newColor</span> <span class="p">});</span>
<span class="p">}</span>
<span class="nx">render</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">Provider</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">ColorContext</span><span class="p">;</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">Provider</span> <span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">color</span><span class="p">}</span><span class="o">></span>
<span class="o"><</span><span class="nx">WelcomeText</span> <span class="o">/></span>
<span class="o"><</span><span class="nx">button</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">onColorChange</span><span class="p">}</span><span class="o">></span><span class="nx">Toggle</span> <span class="nx">color</span><span class="o">!<</span><span class="sr">/button</span><span class="err">>
</span> <span class="o"><</span><span class="sr">/Provider</span><span class="err">>
</span> <span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">App</span><span class="p">;</span>
</code></pre></div></div>
<p>Zwróć uwagę, że w powyższym przykładzie importowany jest, z modułu <code class="highlighter-rouge">ColorContext.js</code>, utworzony przez nas wcześniej obiekt <code class="highlighter-rouge">ColorContext</code>. Następnie, w metodzie <code class="highlighter-rouge">render</code> komponentu <code class="highlighter-rouge">App</code> wykorzystywany jest komponent <code class="highlighter-rouge">Provider</code> dostępny w tym obiekcie.</p>
<p>Komponent <code class="highlighter-rouge">Provider</code> przyjmuje jeden atrybut - <code class="highlighter-rouge">value</code> - do którego przypisujemy aktualną wartość kontekstu. Wartość ta będzie dostępna dla wszystkich “konsumerów”, które zostaną użyte w komponentach-dzieciach (i ich dzieciach, itd.) - zresztą o tym za moment.</p>
<p>W naszym przykładzie do atrybutu <code class="highlighter-rouge">value</code> komponentu <code class="highlighter-rouge">Provider</code> przypisano wartość właściwości <code class="highlighter-rouge">color</code> przechowywanej w stanie komponentu <code class="highlighter-rouge">App</code>. Zauważ, że wartość ta jest zmieniana za każdym razem gdy użytkownik naciśnie przycisk (metoda <code class="highlighter-rouge">onColorChange</code>). W ten sposób zmieniany jest też aktualny kontekst aplikacji, a zmiana ta propagowana jest do “konsumerów” dzieci komponentu <code class="highlighter-rouge">Provider</code>.</p>
<h2 id="komponent-consumer">Komponent <code class="highlighter-rouge">Consumer</code></h2>
<p>Wiemy już jak utworzyć kontekst i udostępnić go w aplikacji - czas teraz ten kontekst skonsumować. Do tego właśnie celu służy komponent <code class="highlighter-rouge">Consumer</code>, który obok komponentu <code class="highlighter-rouge">Provider</code> również dostępny jest jako część obiektu <code class="highlighter-rouge">ColorContext</code> zwracanego z modułu <code class="highlighter-rouge">ColorContext.js</code>. Komponent ten wykorzystamy w komponencie <code class="highlighter-rouge">WelcomeText</code>, który został wyrenderowany w komponencie <code class="highlighter-rouge">App</code> (spójrz na metodę <code class="highlighter-rouge">render</code> w poprzednim przykładzie kodu).</p>
<p>Spójrzmy na przykładową implementację komponentu <code class="highlighter-rouge">WelcomeText</code>:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">React</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">ColorContext</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">./ColorContext</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">WelcomeText</span> <span class="o">=</span> <span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">Consumer</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">ColorContext</span><span class="p">;</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">Consumer</span><span class="o">></span>
<span class="p">{</span><span class="nx">color</span> <span class="o">=></span> <span class="o"><</span><span class="nx">p</span> <span class="nx">style</span><span class="o">=</span><span class="p">{{</span> <span class="nx">color</span> <span class="p">}}</span><span class="o">></span><span class="nx">Hello</span> <span class="nx">world</span><span class="o">!!<</span><span class="sr">/p></span><span class="err">}
</span> <span class="o"><</span><span class="sr">/Consumer</span><span class="err">>
</span> <span class="p">);</span>
<span class="p">};</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">WelcomeText</span><span class="p">;</span>
</code></pre></div></div>
<p>Na powyższym przykładzie widać, że dzieckiem komponentu <code class="highlighter-rouge">Consumer</code> jest <strong>funkcja</strong> (w przypadku Context API jest to wymagane). Funkcja ta przyjmuje jeden parametr, który posiada tę samą wartość, którą przekazaliśmy do komponentu <code class="highlighter-rouge">Provider</code> poprzez atrybut <code class="highlighter-rouge">value</code>. W naszym przykładzie wykorzystujemy go do pokolorowania tekstu.</p>
<blockquote>
<p>Przekazywanie funkcji jako dziecko komponentu to implementacja techniki zwanej “<strong>render props</strong>”. Do tej pory nie pisałem o tym na blogu ale jeśli temat Cię interesuje to więcej znajdziesz w dokumentacji, <a href="https://reactjs.org/docs/render-props.html">pod tym linkiem</a>.</p>
</blockquote>
<p>Oczywiście zmiana wartości <code class="highlighter-rouge">this.state.color</code> w komponencie <code class="highlighter-rouge">App</code> powoduje propagację tej zmiany do wszystkich “konsumerów” komponentu <code class="highlighter-rouge">Provider</code>. Alternatywą dla opisywanego podejścia mogłoby być przekazywanie aktualnego koloru dzieciom komponentu <code class="highlighter-rouge">App</code> poprzez “propsy”. Staje się to jednak mało wygodne jeśli musimy przekazać tę wartość wiele poziomów “głębiej” - w takim przypadku zastosowanie mechanizmu Context API jest <strong>znacznie wygodniejsze</strong>.</p>
<h2 id="context-api-a-sprawa-reduxa">Context API a sprawa Reduxa</h2>
<p>Po przeanalizowaniu powyższych przykładów, możesz dojść do wniosku, że Context API to świetna alternatywa dla Reduxa (i innych implementacji architektury Flux). Dostarcza globalny stan dla aplikacji? Dostarcza! Mniej kodu trzeba napisać aby zaktualizować stan? Mniej! Pytanie więc czy faktycznie możemy używać tych dwóch podejść zamiennie - w końcu, jak mawiał klasyk, <a href="https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367">You Might Not Need Redux</a>…</p>
<p>Odpowiedź jak zwykle brzmi: “to zależy”… Wszystko jak zawsze w programowaniu uwarunkowane jest potrzebami - moim zdaniem, jeśli Twoja aplikacja jest relatywnie mała lub średnia, a globalny stan jest <strong>niewielki</strong>, możesz zamiast wprowadzać Reduxa zastosować Context API. Jeśli jednak wiesz, że aplikacja będzie duża (lub sporo jej stanu będzie musiało być dostępne globalnie), to Redux może okazać się lepszym rozwiązaniem, które poza dostarczaniem globalnego stanu dla aplikacji, dodatkowo pomaga lepiej ustrukturyzować całą aplikację.</p>
<h2 id="podsumowanie">Podsumowanie</h2>
<p>Bardzo mi się podoba sposób, w jaki rozwija się React. Kolejne wersje tej biblioteki wprowadzają kolejne ciekawe usprawnienia, a <strong>Context API</strong> niewątpliwie do nich należy. Wydaje mi się, że warto znać tę technikę bo jest to prosty sposób na wprowadzenie globalnego stanu dla aplikacji.</p>
<p><strong>P.S.</strong> Jak zwykle, przedstawione dziś przykłady kodu można znaleźć na <a href="https://github.com/burczu/react-context-api-example">GitHubie</a> i samodzielnie je “poklikać”.</p>bartek-dybowskiWraz z pojawieniem się wersji v16.3.0 Reacta, do naszych rąk trafiła całkiem nowa i myślę, że całkiem przydatna funkcjonalność. Mowa tutaj o tytułowym Context API, które pozwala na wprowadzenie do aplikacji pewnych globalnych ustawień, od których zależeć mogą niektóre komponenty. Dzięki temu implementacja w aplikacji, na przykład, wielu wersji kolorystycznych staje się dziecinnie prosta. Zresztą sam się za chwilę o tym przekonasz!HOC czyli komponenty wyższego rzędu w React2018-05-29T06:15:00+00:002018-05-29T06:15:00+00:00https://www.nafrontendzie.pl/hoc-czyli-komponenty-wyzszego-rzedu-react<p>Halo, halo! Witam po dłuższej przerwie, spowodowanej… trochę lenistwem, a trochę innymi sprawami życiowymi. No nic to. Najważniejsze, że w końcu wracam do pisania! A tematem dzisiejszego posta są <strong>komponenty wyższego rzędu w React</strong>, czyli z angielska <strong>higher order components</strong> (a skracając: HOC). W wielkim skrócie jest to technika re-używania logiki komponentów, która wbrew pozorom jest dość powszechnie stosowana. Ale o tym w dalszej części tego wpisu.</p>
<h2 id="podstawowe-założenia-hoc">Podstawowe założenia HOC</h2>
<p>Generalnie możemy powiedzieć, że komponent wyższego rzędu w React jest funkcją, która <strong>przekształca jeden komponent w inny komponent</strong>. Przekształcenie to zwykle powoduje “ulepszenie” w jakiś sposób oryginalnego komponentu. Myślę, że więcej wywnioskujesz analizując przykłady - wyobraźmy sobie, że mamy taki oto komponent <code class="highlighter-rouge">App</code>:</p>
<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">React</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">App</span> <span class="o">=</span> <span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="p"><</span><span class="nt">p</span><span class="p">></span>Hello World!!<span class="p"></</span><span class="nt">p</span><span class="p">>;</span>
<span class="p">}</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">App</span><span class="p">;</span>
</code></pre></div></div>
<p>Mogę teraz utworzyć komponent wyższego rzędu, który będzie “ulepszał” ten komponent (umieszczę go w pliku <code class="highlighter-rouge">enhanceApp.js</code>):</p>
<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">React</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="k">export</span> <span class="k">default</span> <span class="p">(</span><span class="nx">Component</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="o">=></span> <span class="p">(</span>
<span class="p"><</span><span class="nt">div</span> <span class="na">style=</span><span class="err"> </span><span class="si">{</span><span class="p">{</span><span class="na">color</span><span class="p">:</span> <span class="dl">'</span><span class="s1">red</span><span class="dl">'</span><span class="p">}</span><span class="si">}</span><span class="p">></span>
<span class="p"><</span><span class="nc">Component</span> <span class="err">{</span><span class="p">...</span><span class="nt">props</span><span class="err">}</span> <span class="p">/></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p">);</span>
<span class="p">};</span>
</code></pre></div></div>
<p>Jak widzisz, z modułu tego eksportuję funkcję przyjmującą oryginalny komponent <strong>jako parametr</strong>. Funkcja ta zwraca nowy komponent funkcyjny (oczywiście dla bardziej zaawansowanych przypadków mogę też zwracać komponent klasowy).</p>
<p>Ten nowy zwracany komponent nie robi nic innego tylko <strong>znacznie</strong> “ulepsza” oryginalny komponent poprzez owinięcie go elementem <code class="highlighter-rouge">div</code>, który nadaje mu o wiele fajniejszy styl. Zwróć uwagę, że do oryginalnego komponentu przekazuję też <strong>wszystkie</strong> właściwości obiektu <code class="highlighter-rouge">props</code> (używam <code class="highlighter-rouge">...</code> czyli operatora “spread”)! W przeciwnym wypadku, użycie HOC powodowałoby utratę informacji przekazywanych z komponentu rodzica.</p>
<p>Zobacz teraz jak używać HOC - robię to w pliku z komponentem <code class="highlighter-rouge">App</code>:</p>
<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">React</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">enhanceApp</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">./enhanceApp</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">App</span> <span class="o">=</span> <span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span>
<span class="p"><</span><span class="nt">p</span><span class="p">></span>Hello World!!<span class="p"></</span><span class="nt">p</span><span class="p">></span>
<span class="p">);</span>
<span class="p">}</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">enhanceApp</span><span class="p">(</span><span class="nx">App</span><span class="p">);</span>
</code></pre></div></div>
<p>Widać tutaj, że użycie komponentu wyższego rzędu sprowadza się do wywołania funkcji i przekazania do niej oryginalnego komponentu. W ten sposób, z powyższego modułu eksportujemy nie oryginalny komponent <code class="highlighter-rouge">App</code>, a <strong>ten już ulepszony</strong> przez HOC <code class="highlighter-rouge">enhanceApp</code>;</p>
<p>I to w zasadzie cała filozofia jeśli chodzi o komponenty wyższego rzędu. Oczywiście komponenty zwracane przez HOC mogą być znacznie bardziej skomplikowane, wykorzystujące metody cyklu życia komponentu itd.. <strong>Wszystko zależy od potrzeb i danej sytuacji</strong>.</p>
<h2 id="studium-przypadku---funkcja-connect">Studium przypadku - funkcja <code class="highlighter-rouge">connect</code></h2>
<p>Na tym co pokazałem powyżej mógłbym już w zasadzie zakończyć, ale pomyślałem, że <strong>jako bonus</strong> spróbujemy zrozumieć zasadę działania jednego z najczęściej stosowanych w praktyce HOC. Chodzi mianowicie o funkcję <code class="highlighter-rouge">connect</code> dostępną w pakiecie <code class="highlighter-rouge">react-redux</code>, która łączy “store” Reduxa z komponentem React. Myślę, że większość programistów pracujących w React, miała z nią styczność lub chociaż mniej więcej ją kojarzy…</p>
<p>Nie będę tutaj pokazywać jej rzeczywistej implementacji, która jest trochę bardziej skomplikowana - tę możesz sprawdzić sam <a href="https://github.com/reduxjs/react-redux/blob/master/src/connect/connect.js" title="implementacja funkcji connect">tutaj</a>. Zamiast tego spróbujemy napisać jej własną, <strong>uproszczoną</strong> wersję. Najpierw jednak przykład kodu, który będzie wykorzystywać naszą własną implementację funkcji <code class="highlighter-rouge">connect</code>:</p>
<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">React</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">connect</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">./custom-connect</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">Connected</span> <span class="o">=</span> <span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="p"><</span><span class="nt">p</span><span class="p">></span><span class="si">{</span><span class="nx">props</span><span class="p">.</span><span class="nx">text</span><span class="si">}</span><span class="p"></</span><span class="nt">p</span><span class="p">>;</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">mapStateToProps</span> <span class="o">=</span> <span class="p">(</span><span class="nx">state</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="p">{</span> <span class="p">...</span><span class="nx">state</span><span class="p">,</span> <span class="na">text</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Hello from fake state!</span><span class="dl">'</span> <span class="p">};</span>
<span class="p">};</span>
<span class="kd">const</span> <span class="nx">mapDispatchToProps</span> <span class="o">=</span> <span class="p">(</span><span class="nx">dispatch</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="p">{};</span> <span class="c1">// no actions defined yet</span>
<span class="p">};</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">connect</span><span class="p">(</span><span class="nx">mapStateToProps</span><span class="p">,</span> <span class="nx">mapDispatchToProps</span><span class="p">)(</span><span class="nx">Connected</span><span class="p">);</span>
</code></pre></div></div>
<p>Jeśli znasz trochę zasady programowania funkcyjnego to zauważysz, że zastosowano tutaj tzw. “curry’ing” czyli “funkcja zwracająca funkcję”. Do funkcji <code class="highlighter-rouge">connect</code> przekazujemy bowiem referencje do metod mapujących i dopiero <strong>do wyniku jej działania</strong> przekazujemy komponent <code class="highlighter-rouge">Connected</code>.</p>
<p>W powyższym przykładzie widać też, że funkcja <code class="highlighter-rouge">mapStateToProps</code> wzbogaca stan o właściwość <code class="highlighter-rouge">text</code>, z której korzysta komponent <code class="highlighter-rouge">Connected</code>. Aby jednak właściwość ta była dostępna dla komponentu, musimy zaimplementować naszą funkcję <code class="highlighter-rouge">connect</code>, która uruchomi funkcje mapujące i ich wyniki <strong>dorzuci</strong> do “propsów”. Zastanówmy się więc teraz, jak można by to zaimplementować (plik <code class="highlighter-rouge">custom-connect.js</code>):</p>
<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">React</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="c1">// fake Redux stuff for the example purposes</span>
<span class="kd">const</span> <span class="nx">fakeState</span> <span class="o">=</span> <span class="p">{};</span>
<span class="kd">const</span> <span class="nx">fakeDispatch</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{};</span>
<span class="k">export</span> <span class="k">default</span> <span class="p">(</span><span class="nx">mapStateToProps</span><span class="p">,</span> <span class="nx">mapDispatchToProps</span><span class="p">)</span> <span class="o">=></span> <span class="p">(</span><span class="nx">Component</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// the main purpose of this HOC - add Redux stuff to the Component's props</span>
<span class="kd">const</span> <span class="nx">newProps</span> <span class="o">=</span> <span class="p">{</span>
<span class="p">...</span><span class="nx">props</span><span class="p">,</span>
<span class="p">...</span><span class="nx">mapStateToProps</span><span class="p">(</span><span class="nx">fakeState</span><span class="p">),</span>
<span class="p">...</span><span class="nx">mapDispatchToProps</span><span class="p">(</span><span class="nx">fakeDispatch</span><span class="p">)</span>
<span class="p">};</span>
<span class="k">return</span> <span class="p"><</span><span class="nc">Component</span> <span class="err">{</span><span class="p">...</span><span class="nt">newProps</span><span class="err">}</span> <span class="p">/>;</span>
<span class="p">};</span>
<span class="p">};</span>
</code></pre></div></div>
<p><strong>Szybkie wyjaśnienie</strong>: tak jak wspomniałem wcześniej, funkcja <code class="highlighter-rouge">connect</code> wykorzystuje “curry’ing” stąd zapis w stylu:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">example</span> <span class="o">=</span> <span class="p">(</span><span class="nx">arg1</span><span class="p">)</span> <span class="o">=></span> <span class="p">(</span><span class="nx">arg2</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span> <span class="p">;</span>
</code></pre></div></div>
<p>Dla nie obeznanych z funkcjami strzałkowymi, jest to <strong>tożsame</strong> z zapisem:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">example</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">arg1</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">arg2</span><span class="p">)</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>No ale wracając do rzeczy… zauważ, że na początku deklaruję stałe <code class="highlighter-rouge">fakeState</code> oraz <code class="highlighter-rouge">fakeDispatch</code> - oczywiście w oryginale wykorzystywane są odpowiednie funkcje dostarczane przez Reduxa.</p>
<p>Dalej mamy już właściwą implementację funkcji <code class="highlighter-rouge">connect</code> (domyślny eksport), która przyjmuje jako parametry referencje do funkcji mapujących, a następnie zwraca funkcję, do której przekazywany jest oryginalny komponent (<code class="highlighter-rouge">Component</code>).</p>
<p>Ta funkcja z kolei, zwraca <strong>nowy komponent funkcyjny</strong>, w którym tworzony jest obiekt <code class="highlighter-rouge">newProps</code>. Korzystając z operatora “spread” kopiuję do niego <strong>wszystkie</strong> właściwości oryginalnych “propsów” oraz właściwości obiektów zwracanych przez funkcje mapujące.</p>
<p>Na koniec, ponownie korzystając operatora “spread”, przekazuję wszystkie właściwości obiektu <code class="highlighter-rouge">newProps</code> jako atrybuty wywołania komponentu <code class="highlighter-rouge">Component</code>. W ten sposób funkcja <code class="highlighter-rouge">connect</code> rozszerza “propsy” oryginalnego komponentu.</p>
<h2 id="podsumowanie">Podsumowanie</h2>
<p>I to wszystko na dziś. Mam nadzieję, że to co pokazałem jest zrozumiałe - jeśli nie, śmiało pisz w komentarzach lub bezpośrednio do mnie, na e-mail. Wydaje mi się, że koncepcja komponentów wyższego rzędu jest bardzo przydatna - na przykład kiedy potrzebujemy mieć mechanizm, który rozszerza część naszych komponentów w określony sposób. Dlatego też warto ją znać!</p>
<p><strong>P.S.</strong> Jak zawsze <strong>udostępniam na GitHubie</strong> kod przedstawionych dziś przykładów do samodzielnego przetestowania. Odpowiednie repozytorium znajdziesz <a href="https://github.com/burczu/react-higher-order-components-example" title="repozytorium z przykładami">pod tym linkiem</a>.</p>bartek-dybowskiHalo, halo! Witam po dłuższej przerwie, spowodowanej… trochę lenistwem, a trochę innymi sprawami życiowymi. No nic to. Najważniejsze, że w końcu wracam do pisania! A tematem dzisiejszego posta są komponenty wyższego rzędu w React, czyli z angielska higher order components (a skracając: HOC). W wielkim skrócie jest to technika re-używania logiki komponentów, która wbrew pozorom jest dość powszechnie stosowana. Ale o tym w dalszej części tego wpisu.React Suspense - nowe API już niedługo!2018-03-07T14:50:00+00:002018-03-07T14:50:00+00:00https://www.nafrontendzie.pl/react-suspense-nowe-api-juz-niedlugo<p>Dziś znów krótko… no ale lepszy rydz niż nic! Jeśli jesteś na czasie z nowościami w świecie React, śledzisz Twittera itp., to na pewno zauważyłeś ostatnio spore zamieszane związane z nowym “ficzerem” jaki ma się niebawem pojawić w ramach biblioteki React. Nosi on nazwę <strong>React Suspense</strong> i mówiąc w skrócie, ma pozwalać na opóźnienie renderowania części aplikacji dopóki nie zostanie spełniony określony warunek.</p>
<p>Zresztą, najlepiej będzie jeśli obejrzysz wystąpienie Dana Abramova na konferencji <a href="https://2018.jsconf.is/" title="Strona konferencji JSConf Iceland">JSConf Iceland</a>, w którym przedstawił on nowe API:</p>
<div class="video-wrapper">
<iframe width="560" height="315" src="https://www.youtube.com/embed/v6iR3Zk4oDY" frameborder="0" allowfullscreen=""></iframe>
</div>
<p>Moim zdaniem, nic dziwnego, że jest to ostatnio tak gorący temat - React Suspense pozwoli na tworzenie interfejsu użytkownika, ze <strong>znacznie lepszym UX</strong>. Obecnie standardem jest, że podczas asynchronicznego pobierania danych z serwera (AJAX) pokazywany jest “loader”. Posiadając jednak bardzo szybkie łącze internetowe często zdarza się, że ów “loader” pojawia się tylko na ułamek sekundy… Dzięki opóźnieniu renderowania, na przykład o sekundę, można zwiększyć prawdopodobieństwo, że dane załadują się jeszcze przed pojawieniem się “loadera”.</p>
<p>BTW: ostatnio zaimplementowałem podobne rozwiązanie w projekcie, w którym biorę udział - fajnie, że niedługo będzie ono dostępne “z pudełka”!</p>
<p><strong>P.S.1</strong> Na koniec jeszcze link do przydatnego źródła - na temat React Suspense <a href="https://medium.com/@baphemot/understanding-react-suspense-1c73b4b0b1e6" title="Bartosz Szczeciński na temat React Suspense">napisał już Bartosz Szczeciński</a> i <strong>moim zdaniem warto</strong> zapoznać się z tym artykułem.</p>
<p><strong>P.S.2</strong> Trzeba też dodać, że opisywany “ficzer” jest wciąż w fazie “alfa” i jego ostateczna wersja może się jeszcze zmienić. <strong>Nie jest to więc coś, co można już bezpiecznie używać “na produkcji”!</strong></p>bartek-dybowskiDziś znów krótko… no ale lepszy rydz niż nic! Jeśli jesteś na czasie z nowościami w świecie React, śledzisz Twittera itp., to na pewno zauważyłeś ostatnio spore zamieszane związane z nowym “ficzerem” jaki ma się niebawem pojawić w ramach biblioteki React. Nosi on nazwę React Suspense i mówiąc w skrócie, ma pozwalać na opóźnienie renderowania części aplikacji dopóki nie zostanie spełniony określony warunek.Server Side Rendering w React #5 - Next.js2018-02-19T05:10:00+00:002018-02-19T05:10:00+00:00https://www.nafrontendzie.pl/server-side-rendering-react-5-nextjs<p>Dzisiejszym wpisem zakończymy serię o <strong>Server Side Rendering w React</strong>. W zasadzie to po poprzednich 4 wpisach wiesz już wszystko by stworzyć swoją pierwszą aplikację izomorficzną React. Postanowiłem jednak, że pokażę Ci jeszcze pewną <strong>alternatywę</strong> do tego, co zostało dotychczas pokazane. Istnieje bowiem coś takiego, jak Next.js, czyli specjalny framework pozwalający w łatwy sposób stworzyć aplikację React, która “z pudełka” posiada obsługę renderowania po stronie serwera!</p>
<h2 id="wprowadzenie-do-nextjs">Wprowadzenie do Next.js</h2>
<p>Czym jest <a href="https://github.com/zeit/next.js/" title="Repozytorium projektu Next.js na Githubie">Next.js</a> wyjaśniłem już w sumie w jednym zdaniu we wstępie do tego wpisu… Ogólnie więc jest to <strong>minimalistyczny</strong> framework wykorzystujący takie biblioteki jak <a href="https://reactjs.org/" title="Strona domowa projektu React">React</a>, <a href="https://webpack.js.org/" title="Strona domowa projektu webpack">webpack</a> oraz <a href="https://babeljs.io/" title="Strona domowa projektu Babel">Babel</a> i udostępniający, m.in.:</p>
<ul>
<li><strong>domyślne</strong> renderowanie po stronie klienta jak i serwera (SSR)</li>
<li><strong>automatyczne</strong> dzielenie kodu na paczki (“code splitting” - pod spodem i tak jest webpack)</li>
<li>prosty system <strong>routingu</strong></li>
<li>środowisko deweloperskie oparte o webpackowy “Hot Module Replacement” (HMR)</li>
</ul>
<p>Jak dla mnie wygląda to na całkiem fajny zestaw opcji pozwalający na stworzenie swojej pierwszej <strong>aplikacji izomorficznej</strong>!</p>
<h3 id="instalacja">Instalacja</h3>
<p>Aby rozpocząć pracę z frameworkiem wystarczy zainstalować Next.js oraz React - ja to robie przy pomocy <a href="https://yarnpkg.com/lang/en/" title="Strona domowa projektu Yarn">Yarn</a>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yarn add next react react-dom
</code></pre></div></div>
<p>Równie dobrze możesz jednak użyć <a href="https://www.npmjs.com/" title="Strona domowa projektu npm">npm</a>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm install --save next react react-dom
</code></pre></div></div>
<h3 id="podstawowa-konfiguracja">Podstawowa konfiguracja</h3>
<p>Mając już zainstalowane niezbędne pakiety, <strong>warto</strong> jeszcze zdefiniować sobie trzy przydatne skrypty npm. Aby to zrobić, dodajmy do pliku <code class="highlighter-rouge">package.json</code> sekcję “scripts”:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">"scripts"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"dev"</span><span class="p">:</span><span class="w"> </span><span class="s2">"next"</span><span class="p">,</span><span class="w">
</span><span class="nl">"build"</span><span class="p">:</span><span class="w"> </span><span class="s2">"next build"</span><span class="p">,</span><span class="w">
</span><span class="nl">"start"</span><span class="p">:</span><span class="w"> </span><span class="s2">"next start"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Skrypt <code class="highlighter-rouge">dev</code> odpala po prostu polecenie <code class="highlighter-rouge">next</code>, które uruchomi naszą aplikację <strong>w trybie deweloperskim</strong>. W trybie tym mamy oczywiście skonfigurowany HMR, nie trzeba więc będzie odświeżać strony po każdej zmianie w kodzie.</p>
<p>Skrypt “build” służy do zbudowania <strong>produkcyjnej</strong> wersji aplikacji (domyślnie do katalogu <code class="highlighter-rouge">.next</code> ale można też skonfigurować inny katalog dla “buildów”). Skrypt “start” odpala natomiast <strong>serwer Next.js</strong> (lub inny, na przykład <a href="https://expressjs.com/" title="Strona domowa projektu ExpressJS">ExpressJS</a> - istnieje taka możliwość ale objaśnienie jak to zrobić wykracza poza ramy tego wpisu).</p>
<h3 id="pierwszy-komponent-react">Pierwszy komponent React</h3>
<p>OK. Mamy już wszystko zainstalowane i skonfigurowane. Czas wreszcie przejść do utworzenia pierwszego <strong>prostego</strong> komponentu i uruchomienia aplikacji. Aby to zrobić, w głównym katalogu projektu utwórzmy katalog <code class="highlighter-rouge">pages</code> (dlaczego taki, a nie inny wyjaśnię za chwilę). Następnie w katalogu tym umieśćmy plik <code class="highlighter-rouge">index.js</code> zawierający taki oto komponent React:</p>
<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">Index</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span>
<span class="p"><</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">hr</span> <span class="p">/></span>
<span class="p"><</span><span class="nt">div</span><span class="p">></span>Hello world!<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p">);</span>
<span class="p">}</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">Index</span><span class="p">;</span>
</code></pre></div></div>
<p>Na potrzeby wpisu wystarczy nam bardzo prosty bezstanowy komponent funkcyjny (ang. “stateless functional component”). Zwróć uwagę, że plik ten <strong>nie zawiera</strong> importu z pakietu <code class="highlighter-rouge">react</code>, jak to zwykle robimy w komponentach, w których używamy składni JSX. W Next.js nie ma potrzeby go importować, bo framework robi to za nas.</p>
<p>No dobra, to już wszystko! Możemy odpalić aplikację - skorzystajmy z utworzonego wcześniej skryptu npm:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yarn dev
</code></pre></div></div>
<p>Powyższe polecenie uruchomi serwer Next.js, standardowo na porcie 3000 (czyli lokalnie aplikacja będzie dostępna pod adresem <code class="highlighter-rouge">http://localhost:3000</code>. Oczywiście utworzony przez nas komponent zostanie wyrenderowany <strong>po stronie serwera</strong>, ponieważ w Next.js SSR działa domyślnie.</p>
<h2 id="routing">Routing</h2>
<p>Tak jak wspomniałem, Next.js dostarcza też <strong>prosty routing</strong>. Jak to działa? Już wyjaśniam - powyżej, tworząc nasz pierwszy komponent, umieściłem go w katalogu <code class="highlighter-rouge">pages</code>. Ma to bezpośredni związek z routingiem aplikacji! Otóż każdy, znajdujący się tam komponent odpowiada za jedną ścieżkę, której nazwę definiuje nazwa pliku z komponentem… Czyli: nasz plik <code class="highlighter-rouge">pages/index.js</code> to strona domowa <code class="highlighter-rouge">/</code>; jeśli dodamy plik <code class="highlighter-rouge">pages/test.js</code> to znajdujący się w nim komponent będzie dostępny pod adresem <code class="highlighter-rouge">/test</code> itd.</p>
<p>Przetestujmy to więc. Do katalogu <code class="highlighter-rouge">pages</code> dodajmy plik <code class="highlighter-rouge">about.js</code>:</p>
<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">Link</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">next/link</span><span class="dl">'</span><span class="p">;</span>
<span class="k">export</span> <span class="k">default</span> <span class="p">()</span> <span class="o">=></span> <span class="p">(</span>
<span class="p"><</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nc">Link</span> <span class="na">href=</span><span class="s2">"/"</span><span class="p">><</span><span class="nt">a</span><span class="p">></span>Home<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nc">Link</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">hr</span> <span class="p">/></span>
<span class="p"><</span><span class="nt">div</span><span class="p">></span>About the page here!<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p">);</span>
</code></pre></div></div>
<p>Powyższy komponent również jest całkiem prosty. Zwróć jednak uwagę na import komponentu <code class="highlighter-rouge">Link</code> - jest to specjalny komponent dostarczany przez Next.js i służy do <strong>tworzenia linków</strong> przekierowujących pomiędzy poszczególnymi ścieżkami aplikacji.</p>
<p>Aby łatwiej poruszać się po naszej aplikacji, zmieńmy również nieco implementację komponentu <code class="highlighter-rouge">Index</code>. Tutaj również wykorzystamy komponent <code class="highlighter-rouge">Link</code>:</p>
<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">Link</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">next/link</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">Index</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span>
<span class="p"><</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nc">Link</span> <span class="na">href=</span><span class="s2">"/about"</span><span class="p">><</span><span class="nt">a</span><span class="p">></span>About<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nc">Link</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">hr</span> <span class="p">/></span>
<span class="p"><</span><span class="nt">div</span><span class="p">></span>Hello world!<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p">);</span>
<span class="p">}</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">Index</span><span class="p">;</span>
</code></pre></div></div>
<p>Jeśli teraz uruchomimy aplikację zauważysz, że pod adresem <code class="highlighter-rouge">/about</code> renderowany jest utworzony przed chwilą komponent wyświetlający informacje o stronie. Dodane przez nas linki umożliwiają natomiast nawigację pomiędzy stroną domową a “about” bez przeładowania strony.</p>
<h1 id="podsumowanie">Podsumowanie</h1>
<p>Next.js ma <strong>znacznie więcej</strong> możliwości niż przedstawiłem w dzisiejszym wpisie. Nie chodziło mi jednak o pokazanie jego wszystkich zalet, a jedynie o “zajawienie”, że istnieje tego rodzaju alternatywa.</p>
<p>Jeśli temat Cię zainteresował to <strong>zachęcam</strong> do jego zgłębienia - dużo informacji znajdziesz w pliku <code class="highlighter-rouge">README.ms</code> w <a href="https://github.com/zeit/next.js/" title="Repozytorium projektu Next.js">repozytorium projektu</a>. Istnieje też <a href="https://learnnextjs.com/" title="Strona pozwalająca nauczyć się Next.js">specjalna strona</a>, stworzona przez autorów tego projektu, pozwalająca poznać wszystkie niuanse tego frameworka.</p>
<p>Jako ciekawostkę dodam, że <strong>w oparciu o pomysł</strong> na framework Next.js powstał też framework <a href="https://nuxtjs.org/guide" title="Strona projektu Nuxt.js">Nuxt.js</a> - z grubsza pozwalający na to samo tylko w aplikacjach pisanych z użyciem <a href="https://vuejs.org/" title="Strona projektu Vue.js">Vue.js</a>!</p>
<hr />
<p><strong>P.S.1</strong> Jestem ciekaw jak szeroko stosuje się to rozwiązanie w projektach komercyjnych - jeśli u Ciebie w projekcie korzystacie z Next.js, napisz proszę w komentarzach o swoich wrażeniach!</p>
<p><strong>P.S.2</strong> Kod, który dziś pokazałem jak zwykle znajdziesz na GitHubie do samodzielnego “pobawienia się”. Repozytorium to znajduje się <a href="https://github.com/burczu/react-ssr-nextjs" title="Repozytorium zawierające dzisiejsze przykłady">pod tym linkiem</a>.</p>
<p><strong>P.S.3</strong> Ten wpis jest częścią serii wpisów na temat Server Side Renderingu w React! Poniżej lista wszystkich wpisów tej serii:</p>
<ul>
<li><a href="https://www.nafrontendzie.pl/server-side-rendering-react-1-wprowadzenie" title="Server Side Rendering w React #1 - wprowadzenie">Server Side Rendering w React #1 - wprowadzenie</a></li>
<li><a href="https://www.nafrontendzie.pl/server-side-rendering-react-2-expressjs" title="Server Side Rendering w React #2 - ExpressJS">Server Side Rendering w React #2 - ExpressJS</a></li>
<li><a href="https://www.nafrontendzie.pl/server-side-rendering-react-3-redux" title="Server Side Rendering w React #3 - Redux">Server Side Rendering w React #3 - Redux</a></li>
<li><a href="https://www.nafrontendzie.pl/server-side-rendering-react-4-react-router" title="Server Side Rendering w React #4 - react-router">Server Side Rendering w React #4 - react-router</a></li>
<li><a href="https://www.nafrontendzie.pl/server-side-rendering-react-5-nextjs" title="Server Side Rendering w React #5 - Next.js">Server Side Rendering w React #5 - Next.js</a></li>
</ul>bartek-dybowskiDzisiejszym wpisem zakończymy serię o Server Side Rendering w React. W zasadzie to po poprzednich 4 wpisach wiesz już wszystko by stworzyć swoją pierwszą aplikację izomorficzną React. Postanowiłem jednak, że pokażę Ci jeszcze pewną alternatywę do tego, co zostało dotychczas pokazane. Istnieje bowiem coś takiego, jak Next.js, czyli specjalny framework pozwalający w łatwy sposób stworzyć aplikację React, która “z pudełka” posiada obsługę renderowania po stronie serwera!Gwiazdy JavaScriptu w 2017 roku2018-01-19T05:10:00+00:002018-01-19T05:10:00+00:00https://www.nafrontendzie.pl/gwiazdy-javascriptu-2017-roku<p>Dziś będzie krótko! Bardzo prawdopodobne, że już o tym słyszałeś - sam publikowałem tę informację u siebie na <a href="https://twitter.com/nafrontendzie" title="moje konto na Twitterze">Twitterze</a> - ale zostało opublikowane bardzo ciekawe zestawienie <strong>najpopularniejszych</strong> projektów świata JavaScript znajdujących się na GitHubie. Myślę, że warto się z nim zapoznać - kto wie, może nie słyszałeś, o którymś z tych projektów, a bardzo by Ci się on przydał?</p>
<p>Na jakiej podstawie stwierdzono, które projekty są najpopularniejsze? Po prostu policzono ile <strong>nowych</strong> “gwiazdek” zyskały poszczególne z nich w przeciągu ostatnich 12 miesięcy. Oprócz ogólnego zestawienia mamy też podział na frameworki front-endowe, frameworki node.js i kilka innych kategorii.</p>
<p>A który JavaScriptowy projekt zyskał w zeszłym roku największą popularność? Otóż okazuje się, że <strong><a href="https://vuejs.org/" title="strona projektu Vue.js">Vue.js</a> (+40.0 tys. “gwiazdek”)</strong>! Na drugim miejscu <a href="https://reactjs.org/" title="strona projektu React">React</a> (+27.8 tys. “gwiazdek”), a na trzecim <a href="https://github.com/facebookincubator/create-react-app" title="strona projektu create-react-app na GitHubie">create-react-app</a> (+22.5 tys. “gwiazdek”). To pokazuje, że z jednej strony “hype” na Vue wciąż trwa - i dobrze bo to świetna biblioteka. Z drugiej strony, zestawienie pokazuje też, że najsilniejszym obecnie “ekosystemem” dysponuje React - sporo bibliotek z czołówki zestawienia jest z nim związanych (wspomniany create-react-app na drugim miejscu, a do tego takie projekty jak np. <a href="https://github.com/zeit/next.js/" title="strona projektu Next.js na GitHubie">Next.js</a> czy <a href="https://redux.js.org/" title="strona projektu Redux na GitHubie">Redux</a>). Co ciekawe, <a href="https://angular.io/" title="strona projektu Angular">Angular</a> znalazł się <strong>dopiero na 18 miejscu</strong> zestawienia…</p>
<p>Na koniec linki - moim zdaniem warto zajrzeć:</p>
<ul>
<li><strong>zestawienie <a href="https://risingstars.js.org/2017/en/">2017 JavaScript Rising Stars</a></strong></li>
<li>autorzy zestawienia <a href="https://medium.freecodecamp.org/we-compiled-stats-for-the-top-javascript-projects-of-2017-heres-what-we-learned-441a1b77468c">napisali też o nim wpis</a></li>
<li>o tym, i kilku innych zestawieniach <a href="https://jakubjurkian.pl/front-end-2017/">napisał też Jakub Jurkian</a></li>
</ul>bartek-dybowskiDziś będzie krótko! Bardzo prawdopodobne, że już o tym słyszałeś - sam publikowałem tę informację u siebie na Twitterze - ale zostało opublikowane bardzo ciekawe zestawienie najpopularniejszych projektów świata JavaScript znajdujących się na GitHubie. Myślę, że warto się z nim zapoznać - kto wie, może nie słyszałeś, o którymś z tych projektów, a bardzo by Ci się on przydał?Server Side Rendering w React #4 - react-router2018-01-15T05:07:00+00:002018-01-15T05:07:00+00:00https://www.nafrontendzie.pl/server-side-rendering-react-4-react-router<p>Ostatnio dało się odczuć trochę mniejszą moją aktywność na blogu ale to nie znaczy, że z nim kończę (zresztą pisałem już o tym nieco w <a href="https://www.nafrontendzie.pl/krotki-wpis-noworoczny" title="Krótki wpis noworoczny">poście noworocznym</a>). Mam przecież rozpoczętą serię o <strong>Server Side Rendering w React</strong>… A skoro, podobno, mężczyznę poznaje się nie po tym jak zaczyna ale jak kończy, to wydaje mi się, że moim obowiązkiem jest dokończyć to co zacząłem! Dlatego też dziś przedstawiam czwartą cześć moich wpisów na temat SSR, w której pokażę, jak zaprząc do działania bibliotekę <strong>react-router</strong> zarówno po stronie klienta jak i serwera. Zapraszam do lektury!</p>
<h2 id="niezbędne-pakiety">Niezbędne pakiety</h2>
<p>Aby móc korzystać z biblioteki <a href="https://reacttraining.com/react-router/" title="Strona domowa biblioteki react-router">react-router</a> po stronie klienta jak i serwera, muszę doinstalować do naszej aplikacji pakiet <code class="highlighter-rouge">react-router-dom</code>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yarn add react-router-dom
</code></pre></div></div>
<p>Powyższe polecenie, oprócz instalacji pakietu <code class="highlighter-rouge">react-router-dom</code> zainstaluje też pakiet <code class="highlighter-rouge">react-router</code> (oraz kilka innych), który wykorzystam w naszej przykładowej aplikacji.</p>
<h2 id="zmiany-w-strukturze-komponentów-i-konfiguracja-routingu">Zmiany w strukturze komponentów i konfiguracja routingu</h2>
<p>W dzisiejszym wpisie przekształcę kod, który powstał jako przykład dla <a href="https://www.nafrontendzie.pl/server-side-rendering-react-3-redux" title="Server Side Rendering w React #3 - Redux">poprzedniego wpisu tej serii</a>, w którym dodałem obsługę Reduxa. Utworzony dotychczas komponent <code class="highlighter-rouge">App</code> przekształcę w komponent <code class="highlighter-rouge">Home</code>, który wyświetlany będzie jako strona domowa. Dodam też nowy komponent <code class="highlighter-rouge">About</code>, który przedstawiać będzie podstronę “o stronie”. Następnie utworzę główny komponent aplikacji, w którym skonfiguję routing. Na koniec zajmę się modyfikacją kodu odpowiedzialnego za renderowanie naszej aplikacji po stronie <strong>serwera</strong> oraz <strong>klienta</strong>.</p>
<h3 id="komponenty-home-oraz-about">Komponenty <code class="highlighter-rouge">Home</code> oraz <code class="highlighter-rouge">About</code></h3>
<p>Na początek zajmę się komponentem <code class="highlighter-rouge">App</code>, który przekształcę w komponent <code class="highlighter-rouge">Home</code>. Tak na prawdę <strong>wystarczy tylko zmienić nazwę</strong> komponentu (oraz pliku, w którym się on znajduje):</p>
<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">React</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">PropTypes</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">prop-types</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">connect</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react-redux</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">class</span> <span class="nx">Home</span> <span class="kd">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
<span class="kd">static</span> <span class="nx">propTypes</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">initialText</span><span class="p">:</span> <span class="nx">PropTypes</span><span class="p">.</span><span class="nx">string</span><span class="p">.</span><span class="nx">isRequired</span><span class="p">,</span>
<span class="na">changeText</span><span class="p">:</span> <span class="nx">PropTypes</span><span class="p">.</span><span class="nx">func</span><span class="p">.</span><span class="nx">isRequired</span>
<span class="p">}</span>
<span class="nx">onButtonClick</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">event</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">changeText</span><span class="p">();</span>
<span class="p">}</span>
<span class="nx">render</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span>
<span class="p"><</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">p</span><span class="p">></span><span class="si">{</span><span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">initialText</span><span class="si">}</span><span class="p"></</span><span class="nt">p</span><span class="p">></span>
<span class="p"><</span><span class="nt">button</span> <span class="na">onClick=</span><span class="si">{</span><span class="k">this</span><span class="p">.</span><span class="nx">onButtonClick</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="k">this</span><span class="p">)</span><span class="si">}</span><span class="p">></span>change text!<span class="p"></</span><span class="nt">button</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">mapStateToProps</span> <span class="o">=</span> <span class="p">(</span><span class="nx">state</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="p">{</span> <span class="p">...</span><span class="nx">state</span> <span class="p">};</span>
<span class="p">};</span>
<span class="kd">const</span> <span class="nx">mapDispatchToProps</span> <span class="o">=</span> <span class="p">(</span><span class="nx">dispatch</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="p">{</span>
<span class="na">changeText</span><span class="p">:</span> <span class="p">()</span> <span class="o">=></span> <span class="nx">dispatch</span><span class="p">({</span> <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">CHANGE_TEXT</span><span class="dl">'</span> <span class="p">})</span>
<span class="p">};</span>
<span class="p">};</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">connect</span><span class="p">(</span><span class="nx">mapStateToProps</span><span class="p">,</span> <span class="nx">mapDispatchToProps</span><span class="p">)(</span><span class="nx">Home</span><span class="p">);</span>
</code></pre></div></div>
<p>Kolejna rzecz, którą zrobię to dodanie <strong>nowego komponentu</strong>, przedstawiającego informacje “o stronie” - dla niepoznaki nazwę go <code class="highlighter-rouge">About</code>. Oto jak on wygląda:</p>
<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">React</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">About</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span>
<span class="p"><</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">h1</span><span class="p">></span>About<span class="p"></</span><span class="nt">h1</span><span class="p">></span>
<span class="p"><</span><span class="nt">p</span><span class="p">></span>Some information about the page<span class="p"></</span><span class="nt">p</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p">);</span>
<span class="p">};</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">About</span><span class="p">;</span>
</code></pre></div></div>
<p>Powyżej widać, że jest to prosty komponent prezentacyjny (funkcyjny). Na potrzeby tego przykładu <strong>nie potrzebuję</strong> aby był on bardziej skomplikowany.</p>
<h3 id="konfiguracja-routingu">Konfiguracja routingu</h3>
<p>Komponenty <code class="highlighter-rouge">Home</code> oraz <code class="highlighter-rouge">About</code> będą wyświetlane odpowiednio dla adresów <code class="highlighter-rouge">/</code> oraz <code class="highlighter-rouge">/about</code>. Routing ten skonfiguruję w głównym komponencie <code class="highlighter-rouge">App</code>, który teraz dodam (stary komponent <code class="highlighter-rouge">App</code> został przed chwilą przemianowany na <code class="highlighter-rouge">Home</code>):</p>
<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">React</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">Route</span><span class="p">,</span> <span class="nx">Link</span><span class="p">,</span> <span class="nx">Switch</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react-router-dom</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">Home</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">./Home</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">About</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">./About</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">App</span> <span class="o">=</span> <span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span>
<span class="p"><</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nc">Link</span> <span class="na">to=</span><span class="s2">"/"</span><span class="p">></span>Home<span class="p"></</span><span class="nc">Link</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nc">Link</span> <span class="na">to=</span><span class="s2">"/about"</span><span class="p">></span>About<span class="p"></</span><span class="nc">Link</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"><</span><span class="nt">hr</span> <span class="p">/></span>
<span class="p"><</span><span class="nc">Switch</span><span class="p">></span>
<span class="p"><</span><span class="nc">Route</span> <span class="na">path=</span><span class="s2">"/about"</span> <span class="na">component=</span><span class="si">{</span><span class="nx">About</span><span class="si">}</span> <span class="p">/></span>
<span class="p"><</span><span class="nc">Route</span> <span class="na">path=</span><span class="s2">"/"</span> <span class="na">component=</span><span class="si">{</span><span class="nx">Home</span><span class="si">}</span> <span class="p">/></span>
<span class="p"></</span><span class="nc">Switch</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p">);</span>
<span class="p">};</span>
<span class="k">export</span> <span class="k">default</span> <span class="nx">App</span><span class="p">;</span>
</code></pre></div></div>
<p>Jak widzisz, nie ma tutaj niczego niezwykłego: korzystam ze <strong>standardowych</strong> komponentów <code class="highlighter-rouge">Route</code> i <code class="highlighter-rouge">Switch</code> dostępnych w pakiecie <code class="highlighter-rouge">react-router-dom</code>. Oprócz tego, dodałem też “menu” nawigacyjne aby łatwiej było się poruszać po aplikacji. Korzystam tutaj z komponentu <code class="highlighter-rouge">Link</code>, który również dostępny jest we wspomnianym pakiecie.</p>
<blockquote>
<p><strong>Uwaga!</strong> Jeśli powyższy przykład nie jest dla Ciebie zrozumiały, proponuję abyś zajrzał do mojego wpisu na temat <a href="https://www.nafrontendzie.pl/react-router-wersji-4-wszystko-nowa" title="React-router w wersji 4 czyli wszystko od nowa...">react-router w wersji 4</a>. To powinno Ci trochę rozjaśnić temat.</p>
</blockquote>
<p>I to wszystko jeśli chodzi o zmiany w strukturze komponentów oraz konfiguracji samego routingu. Teraz czas na…</p>
<h2 id="zmiany-po-stronie-serwera">Zmiany po stronie serwera</h2>
<p>Na początek zajmę się renderowaniem naszej aplikacji <strong>po stronie serwera</strong>. Biblioteka <code class="highlighter-rouge">react-router</code> jest na to przygotowana i dostarcza odpowiednich narzędzi do tego celu. Zresztą spójrz na przykład:</p>
<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">express</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">express</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">path</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">path</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">React</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">ReactDOMServer</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react-dom/server</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">createStore</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">redux</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">Provider</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react-redux</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">reducers</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">./reducers</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">StaticRouter</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react-router</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">Html</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">./components/Html</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">App</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">./components/App</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">express</span><span class="p">();</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="kd">static</span><span class="p">(</span><span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">__dirname</span><span class="p">)));</span>
<span class="nx">app</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">*</span><span class="dl">'</span><span class="p">,</span> <span class="k">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">scripts</span> <span class="o">=</span> <span class="p">[</span><span class="dl">'</span><span class="s1">vendor.js</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">client.js</span><span class="dl">'</span><span class="p">];</span>
<span class="kd">const</span> <span class="nx">initialState</span> <span class="o">=</span> <span class="p">{</span> <span class="na">initialText</span><span class="p">:</span> <span class="dl">"</span><span class="s2">rendered on the server</span><span class="dl">"</span> <span class="p">};</span>
<span class="kd">const</span> <span class="nx">context</span> <span class="o">=</span> <span class="p">{};</span>
<span class="kd">const</span> <span class="nx">store</span> <span class="o">=</span> <span class="nx">createStore</span><span class="p">(</span><span class="nx">reducers</span><span class="p">,</span> <span class="nx">initialState</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">appMarkup</span> <span class="o">=</span> <span class="nx">ReactDOMServer</span><span class="p">.</span><span class="nx">renderToString</span><span class="p">((</span>
<span class="p"><</span><span class="nc">StaticRouter</span> <span class="na">location=</span><span class="si">{</span><span class="nx">req</span><span class="p">.</span><span class="nx">url</span><span class="si">}</span> <span class="na">context=</span><span class="si">{</span><span class="nx">context</span><span class="si">}</span><span class="p">></span>
<span class="p"><</span><span class="nc">Provider</span> <span class="na">store=</span><span class="si">{</span><span class="nx">store</span><span class="si">}</span><span class="p">></span>
<span class="p"><</span><span class="nc">App</span> <span class="p">/></span>
<span class="p"></</span><span class="nc">Provider</span><span class="p">></span>
<span class="p"></</span><span class="nc">StaticRouter</span><span class="p">></span>
<span class="p">));</span>
<span class="kd">const</span> <span class="nx">html</span> <span class="o">=</span> <span class="nx">ReactDOMServer</span><span class="p">.</span><span class="nx">renderToStaticMarkup</span><span class="p">(<</span><span class="nc">Html</span> <span class="na">children=</span><span class="si">{</span><span class="nx">appMarkup</span><span class="si">}</span> <span class="na">scripts=</span><span class="si">{</span><span class="nx">scripts</span><span class="si">}</span> <span class="na">initialState=</span><span class="si">{</span><span class="nx">initialState</span><span class="si">}</span> <span class="p">/>);</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="s2">`<!doctype html></span><span class="p">${</span><span class="nx">html</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="p">});</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="mi">3000</span><span class="p">,</span> <span class="p">()</span> <span class="o">=></span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Listening on localhost:3000</span><span class="dl">'</span><span class="p">));</span>
</code></pre></div></div>
<p>W sumie niewiele się tutaj zmieniło w stosunku do tego co zostało stworzone w poprzednim wpisie tej serii. Jedyne co doszło to import komponentu <a href="https://reacttraining.com/react-router/web/api/StaticRouter" title="Dokumentacja dotycząca komponentu StaticRouter">StaticRouter</a> z pakietu <code class="highlighter-rouge">react-router</code> (nie mylić z <code class="highlighter-rouge">react-router-dom</code>). Komponentem tym “owijam” pozostałe komponenty przekazywane do metody <code class="highlighter-rouge">renderToString</code> oraz przekazuję do niego dwa atrybuty: <code class="highlighter-rouge">location</code> oraz <code class="highlighter-rouge">context</code>.</p>
<p>Do pierwszego z nich przekazuję wartość <code class="highlighter-rouge">url</code> żądania do serwera - w ten sposób react-router <strong>będzie umiał powiązać</strong> adres wpisany w pasku adresu przeglądarki z odpowiednim komponentem i go wyrenderować. Czyli jeśli wpiszemy “z palca” adres <code class="highlighter-rouge">http://example.com/about</code> to już na serwerze ścieżka ta zostanie rozwiązana i naszym oczom ukaże się komponent <code class="highlighter-rouge">About</code> (bez dodatkowych czynności po stronie klienta).</p>
<p>Drugim atrybutem, który przekazuję do komponentu <code class="highlighter-rouge">StaticRouter</code> jest <code class="highlighter-rouge">context</code>. Jest to zwykły obiekt, który zostanie dodany do “propsów” komponentu renderowanego dla danej ścieżki. Może on zostać <strong>zmodyfikowany</strong> podczas renderowania pasującego komponentu. Dla przykładu: jeśli dany adres zostanie powiązany z komponentem, który renderuje komponent <code class="highlighter-rouge">Redirect</code> to do obiektu <code class="highlighter-rouge">context</code> zostanie dodana właściwość <code class="highlighter-rouge">url</code> wskazująca, gdzie należy przekierować; dzięki temu możemy to rozpoznać już podczas przetwarzania żądania do serwera i wykonać przekierowanie “ręcznie”.</p>
<blockquote>
<p><strong>Uwaga!</strong> Więcej na temat obiektu <code class="highlighter-rouge">context</code> (i ogólnie SSR w react-router) przeczytasz <a href="https://reacttraining.com/react-router/web/guides/server-rendering" title="Strona dokumentacji react-router na tema SSR">na tej stronie dokumentacji</a>.</p>
</blockquote>
<h2 id="zmiany-po-stronie-klienta">Zmiany po stronie klienta</h2>
<p>Ok, konfigurację po stronie serwera mamy już “ogarniętą”. Przyszła więc pora na renderowanie <strong>po stronie klienta</strong>. Tutaj nie ma już w zasadzie niczego nowego:</p>
<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">React</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">ReactDOM</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react-dom</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">createStore</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">redux</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">Provider</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react-redux</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">reducers</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">./reducers</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">App</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">./components/App</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">BrowserRouter</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react-router-dom</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">store</span> <span class="o">=</span> <span class="nx">createStore</span><span class="p">(</span><span class="nx">reducers</span><span class="p">,</span> <span class="p">{</span> <span class="p">...</span><span class="nb">window</span><span class="p">.</span><span class="nx">APP_STATE</span> <span class="p">});</span>
<span class="nx">ReactDOM</span><span class="p">.</span><span class="nx">hydrate</span><span class="p">((</span>
<span class="p"><</span><span class="nc">BrowserRouter</span><span class="p">></span>
<span class="p"><</span><span class="nc">Provider</span> <span class="na">store=</span><span class="si">{</span><span class="nx">store</span><span class="si">}</span><span class="p">></span>
<span class="p"><</span><span class="nc">App</span> <span class="p">/></span>
<span class="p"></</span><span class="nc">Provider</span><span class="p">></span>
<span class="p"></</span><span class="nc">BrowserRouter</span><span class="p">></span>
<span class="p">),</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">app</span><span class="dl">'</span><span class="p">));</span>
</code></pre></div></div>
<p>Jak widzisz, tym razem wykorzystuję komponent <code class="highlighter-rouge">BrowserRouter</code> z pakietu <code class="highlighter-rouge">react-router-dom</code>, którym “owijam” komponenty renderowane po stronie przeglądarki. Jeśli pracowałeś już z biblioteką <code class="highlighter-rouge">react-router</code> to wiesz, że <strong>to wystarczy</strong> aby zadziałał routing, który skonfigurowałem w komponencie <code class="highlighter-rouge">App</code> (ponownie odsyłam do <a href="https://www.nafrontendzie.pl/react-router-wersji-4-wszystko-nowa" title="React-router w wersji 4 czyli wszystko od nowa...">mojego wpisu na temat react-rotuter v4</a>).</p>
<h2 id="podsumowanie">Podsumowanie</h2>
<p>I to tyle na dziś. Powyższy przykład przedstawia <strong>najbardziej podstawową</strong> konfigurację routingu, który zadziała zarówno po stronie serwera jak i klienta. Poniżej podaję link do repozytorium na GitHubie, którym możesz się samodzielnie pobawić - gorąco do tego zachęcam!</p>
<p>To jednak jeszcze <strong>nie koniec</strong> serii na temat SSR w React! Planuję jeszcze conajmniej jeden wpis, w którym pokażę bibliotekę <a href="https://github.com/zeit/next.js/" title="Repozytorium biblioteki next.js">next.js</a>…</p>
<blockquote>
<p><strong>Uwaga!</strong> Kod przedstawionego przykładu jest dostępny jako repozytorium w serwisie GitHub - <a href="https://github.com/burczu/react-ssr-router-example" title="Repozytorium z dzisiejszym przykładem">kliknij tutaj</a> aby je zobaczyć.</p>
</blockquote>
<hr />
<p><strong>P.S.</strong> Ten wpis jest częścią serii wpisów na temat Server Side Renderingu w React! Poniżej lista wszystkich wpisów tej serii:</p>
<ul>
<li><a href="https://www.nafrontendzie.pl/server-side-rendering-react-1-wprowadzenie" title="Server Side Rendering w React #1 - wprowadzenie">Server Side Rendering w React #1 - wprowadzenie</a></li>
<li><a href="https://www.nafrontendzie.pl/server-side-rendering-react-2-expressjs" title="Server Side Rendering w React #2 - ExpressJS">Server Side Rendering w React #2 - ExpressJS</a></li>
<li><a href="https://www.nafrontendzie.pl/server-side-rendering-react-3-redux" title="Server Side Rendering w React #3 - Redux">Server Side Rendering w React #3 - Redux</a></li>
<li><a href="https://www.nafrontendzie.pl/server-side-rendering-react-4-react-router" title="Server Side Rendering w React #4 - react-router">Server Side Rendering w React #4 - react-router</a></li>
<li><a href="https://www.nafrontendzie.pl/server-side-rendering-react-5-nextjs" title="Server Side Rendering w React #5 - NextJS">Server Side Rendering w React #5 - NextJS</a></li>
</ul>bartek-dybowskiOstatnio dało się odczuć trochę mniejszą moją aktywność na blogu ale to nie znaczy, że z nim kończę (zresztą pisałem już o tym nieco w poście noworocznym). Mam przecież rozpoczętą serię o Server Side Rendering w React… A skoro, podobno, mężczyznę poznaje się nie po tym jak zaczyna ale jak kończy, to wydaje mi się, że moim obowiązkiem jest dokończyć to co zacząłem! Dlatego też dziś przedstawiam czwartą cześć moich wpisów na temat SSR, w której pokażę, jak zaprząc do działania bibliotekę react-router zarówno po stronie klienta jak i serwera. Zapraszam do lektury!