Tworzenie okna czatu przy użyciu Reacta i haków
Published: 2024-03-07 07:29:46

**Zanim zaczniesz czytać dalej.**.. Ten artykuł z naszego archiwum wykorzystuje nasz PubNub React SDK, ale nowe aplikacje Chat powinny korzystać z naszego dedykowanego [Chat SDK](https://www.pubnub.com/docs/chat/chat-sdk/overview), napisanego w TypeScript i dołączonej [przykładowej aplikacji](https://www.pubnub.com/docs/chat/chat-sdk/build/sample-chat), która wykorzystuje haki.

[Czat](https://pubnub.com/solutions/chat/) jest kluczowym elementem większości interaktywnych aplikacji. Od [aplikacji do opieki](https://pubnub.com/solutions/digital-health/) zdrowotnej, [czatów grupowych](https://www.pubnub.com/solutions/multiuser-collaboration/) po chatboty, komunikacja w czasie rzeczywistym jest oczekiwana od każdej aplikacji dla wielu użytkowników. Integracja tej funkcjonalności jest znacznie bardziej płynna, jeśli od samego początku wybierzesz odpowiedni framework i infrastrukturę. W tym poradniku pokażemy, jak to zrobić - tworząc okno czatu przy użyciu [React](https://reactjs.org/), [Material-UI](https://material-ui.com/) i [PubNub](https://www.pubnub.com/).

Nasza aplikacja pozwoli każdemu łączyć się i rozmawiać w czasie rzeczywistym na dowolnym kanale. Stworzymy ten czat od podstaw przy użyciu frameworka React i komponentów Material-UI. PubNub API służy do obsługi wysyłania i odbierania wiadomości. Te trzy elementy pomogą nam stworzyć nowoczesny i szybki czat.

W tym samouczku wykorzystamy również[Hooks](https://reactjs.org/docs/hooks-intro.html), nowy sposób pisania komponentów React, który redukuje nadmiarowy kod i organizuje powiązane elementy. W dalszej części samouczka wyjaśnię więcej, dlaczego i jak korzystamy z tych nowych funkcji. Po tym samouczku będziemy mieli czat, który pozwoli każdemu, kto ma nazwę kanału, rozmawiać ze sobą. Kanały są reprezentowane w adresie URL i na stronie, więc udostępnianie kanałów jest łatwe!

[![react hooks chat](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jkx/cadaa09d1dbce7a6f13e1fce08cc4a30/react-hooks-chat.gif)](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jkx/cadaa09d1dbce7a6f13e1fce08cc4a30/react-hooks-chat.gif)

Pub/Sub i pobieranie historii
-----------------------------

PubNub zapewnia prostą i niezwykle szybką infrastrukturę do wysyłania wiadomości. PubNub jest używany do łączenia praktycznie nieograniczonej liczby osób lub systemów na całym świecie w czasie krótszym niż ćwierć sekundy. Dziękilicznym dostępnym zestawom SDK, a nawet [centrum zasobów skoncentrowanemu na czatach](https://www.pubnub.com/developers/chat-resource-center/), PubNub obejmuje wieleprzypadków użycia . Tworząc tę aplikację, będziemy używać funkcji Publish/Subscribe do przesyłania wiadomości w czasie rzeczywistym oraz Storage & Playback do przechowywania wiadomości.

**Publikowanie** zapewnia nam możliwość wysyłania wiadomości do tych, którzy słuchają na określonych kanałach. Dowiedz się, jak publikować[w Reakcie](https://www.pubnub.com/docs/sdks/react#publish-and-subscribe).

**Subskrybowanie** to sposób, w jaki mówimy PubNub, że chcemy otrzymywać wiadomości wysyłane na określone kanały. Dowiedz się, jak subskrybować w React[.](https://www.pubnub.com/docs/sdks/react#publish-and-subscribe)

Przechowywanie**i odtwarzanie** oznacza, że ktoś nie musi być subskrybentem w danym momencie, aby otrzymywać wiadomości na kanale. Gdy użytkownik się połączy, możemy pobrać ostatnie wiadomości, aby je wyświetlić! Dowiedz się, jak przechowywać i odtwarzać[wiadomości w](https://www.pubnub.com/docs/react-native-javascript/api-reference-storage-and-playback) Reakcie.

Pierwsze kroki
--------------

W tym przykładzie czatu musimy wykorzystać tylko jedno API dla wszystkich możliwości czatu. Musisz utworzyć konto PubNub za pomocą formularza osadzonego poniżej lub zalogować się, jeśli masz już konto.

Najpierw należy uzyskać unikalne klucze pub/sub w [panelu administratora,](https://admin.pubnub.com/) a następnie włączyć opcję przechowywania i odtwarzania w lewym dolnym rogu strony opcji klucza. Ustawiłem czas przechowywania moich wiadomości na jeden dzień, ale możesz wybrać dowolne ramy czasowe, które będą dla Ciebie najlepsze. Pamiętaj, aby zapisać zmiany.

Teraz możemy rozpocząć konfigurację naszego projektu React.

### Jak zainstalować React.js i PubNub

Aby zainstalować React.js i PubNub, musimy najpierw upewnić się, że mamy Node.js i npm. Zainstaluj je na [oficjalnej stronie Node.js](https://nodejs.org/en/). Jeśli już je zainstalowałeś, upewnij się, że Twoja wersja npm jest wyższa niż 5.2, wpisując

```js
npm -v
```

w terminalu. Teraz mamy nasze menedżery pakietów do stworzenia naszej aplikacji React i zainstalowania naszego PubNub SDK.

Po zainstalowaniu Node.js uruchom te polecenia, aby utworzyć projekt i zainstalować niezbędne moduły. Poczekaj, aż React zbuduje twoją stronę internetową! Gdy to zrobisz, druga linia zainstaluje PubNub. Trzecia zainstaluje nasz framework stylizacji Material-UI.

```js
npx create-react-app <your-app-name>
cd <your-app-name>
npm install --save pubnub
npm install @material-ui/core
```

Mamy teraz wszystko, czego potrzebujemy, aby rozpocząć kodowanie! Jeśli wpiszesz

```js
npm start
```

w terminalu i klikniesz link, który poda po zakończeniu uruchamiania, powinieneś zobaczyć pustą stronę react! Przejdźmy do kodowania!

Dlaczego warto używać React Hooks?
----------------------------------

Przed październikiem 2018 roku do przechowywania[zmiennych lokalnych trzeba było używać komponentów klas](https://reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class). Hooki dały nam możliwość zapisywania stanu wewnątrz komponentów funkcjonalnych i usunęły znaczną część nadmiaru związanego z klasami.

Hooki ułatwiają tworzenie aplikacji na dużą skalę, a ich funkcje pomagają nam grupować podobny kod. Organizujemy logikę w naszych komponentach według tego, co robią, a nie kiedy muszą to zrobić. Rezygnujemy zezwykłych funkcji cyklu życia, takich jak componentDidMounticomponentDidUpdate , azamiast tego używamy useEffect.

useEffect jest jednym z dwóch głównych haków, których używamy, drugim jest useState. useState jest nowym setState, ale działa nieco inaczej. [Dokumentacja haków Reacta](https://reactjs.org/docs/hooks-intro.html) zawiera szczegółowe informacje na temat kilku innych, ale kolejną wspaniałą częścią haków jest to, że możemy tworzyć własne! Pozwala to zaoszczędzić czas i linie kodu, wykorzystując to, co już zrobiliśmy.

W tym poradniku pokażę ci, jak używać useEffect, useState i tworzyć własne hooki!

Tworzenie własnego haka React
-----------------------------

Zacznijmy od stworzenia własnego haka, który uprości nam kod w przyszłości. Zamiast tworzyć funkcje onChange osobno dla każdego wejścia, zbierzmy to, co możemy dla każdego z nich teraz, w jednym haku!

Jeśli zajrzysz do folderu projektu, który utworzyliśmy, zobaczysz, że mamy kilka różnych folderów. Przejdź do folderu "src" i utwórz tam nowy plik o nazwie "useInput.js". Zasady dotyczące haków mówią, że wszystkie haki muszą zaczynać się od "use". Stwierdza również, że haki powinny być używane tylko na najwyższym poziomie, więc nie możemy ich używać w funkcjach, warunkach ani pętlach. Nie możemy również wywoływać ich ze zwykłych funkcji JS, tylko z komponentów funkcji Reacta i niestandardowych haków! Teraz, gdy znamy już ogólne zasady ich działania, stwórzmy jeden z nich!

W tym hooku użyjemy haka useState. Zaimportuj useState z "react" na górze pliku i po utworzeniu funkcji o nazwie, zgadłeś, "useInput".

```js
import { useState } from 'react';
function useInput()
{
  //Define our Hook
}
```

W tym miejscu możemy trochę poszaleć ze składnią. Możemy użyć przypisania destrukturyzującego, aby otrzymać dwa obiekty, które daje nam useState, używając tylko jednej linii kodu. Ale co daje nam useState? Zasadniczo zwraca getter i setter, zmienną zawierającą wartość i funkcję do jej ustawienia! Zamiast uzyskiwać dostęp do naszego stanu przez

```js
this.state.xxxxx
```

możemy uzyskać do niego dostęp za pomocą samej nazwy.

```js
let [value, setValue] = useState('');
```

Tworzymy wyrażenie funkcji przypisane do nowej zmiennej, którą utworzyliśmy o nazwie onChange. Przekazujemy "zdarzenie" przez funkcję, a wewnątrz ustawiamy wartość naszego stanu na wartość docelową zdarzenia. Następnie zwróćmy trzy utworzone przez nas zmienne/funkcje: value, setValue i onChange.

```js
let onChange = function(event){
  setValue(event.target.value);
};
return {
  value,
  setValue,
  onChange
};
```

Wreszcie

```js
export default useInput;
```

na końcu naszego pliku, aby udostępnić go naszej głównej aplikacji!

Projektowanie naszych komponentów React
---------------------------------------

Teraz, gdy mamy już ukończony nasz Hook. Skonfigurujmy nasz plik App.js! Mamy kilka kluczowych plików do zaimportowania na początku naszego pliku: React i dwa domyślne haki, których potrzebujemy, nasz hak useInput, który właśnie utworzyliśmy, nasz plik App.css, PubNub i komponenty Material-UI.

Zastąp to, co znajduje się w pliku App.css, następującymi elementami.

```js
* {
  margin: 0;
  padding: 0;
}
body {
  width: 500px;
  margin: 30px auto;
  background-color: #fff;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
    "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
    monospace;
}
.top {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
}
```

Stwórzmy zarys naszego czatu przy użyciu nagłówków komponentów funkcjonalnych. Pomoże nam to określić, jaki rodzaj projektu i przepływu chcemy dla naszego czatu. Wybrałem trzy różne komponenty: App, Log i Message.

Aplikacja zawiera dziennik, dane wejściowe i przycisk przesyłania. Log zawiera listę wiadomości, a Message wyświetla wiadomość i kto ją wysłał. Upewnij się, że zaimportowałeś wymagane moduły na początku swojego pliku!

```js
//These are the two hooks we use the most of through this Chat
import React, { useState, useEffect} from 'react';
//has a few css stylings that we need.
import './App.css';
//This is a hook we created to reduce some of the bloat we get with watching inputs for changes.
import useInput from './useInput.js';
//Lets us import PubNub for our chat infrastructure capabailites.
import PubNub from 'pubnub';
//Material UI Components
import {Card, CardActions, CardContent,List, ListItem,Button,Typography,Input} from '@material-ui/core';
// Our main Component, the parent to all the others, the one to rule them all.
function App(){
  //Bunch of functions!
  //return()
}
//Log functional component that contains the list of messages
function Log(props){
  //return()
}
//Our message functional component that formats each message.
function Message(props){
  //return()
}
```

Każdy z tych komponentów zawiera funkcję zwrotną, która pozwala nam zaprojektować wygląd każdego z nich. Możemy powiedzieć, jakie informacje przekazujemy od naszych rodziców do naszych dzieci. Dzięki takiemu projektowi przekazujemy informacje tylko w dół, dając każdemu komponentowi to, czego potrzebuje do działania.

Konfiguracja komponentu App Component: Stan z hakami React
----------------------------------------------------------

Nasza aplikacja jest naszym głównym komponentem czatu React. W przypadku tego komponentu musimy skonfigurować kilka rzeczy, takich jak sprawdzenie adresu URL pod kątem wszelkich zmian w kanale, skonfigurowanie naszych stanów, a następnie możemy utworzyć kilka funkcji useEffect, aby określić, co chcemy, aby aplikacja robiła i kiedy to wszystko się dzieje.

Pierwszym działaniem wewnątrz naszej aplikacji jest utworzenie domyślnego kanału. "Globalny" to dobry wybór. Następnie należy sprawdzić adres URL kanału. Jeśli go nie ma, możemy pozostawić domyślny bez zmian, ale jeśli jest, ustawiamy domyślny kanał na ten.

```js
let defaultChannel = "Global";
//Access the parameters provided in the URL
let query = window.location.search.substring(1);
let params = query.split("&");
for(let i = 0; i < params.length;i++){
  var pair = params[i].split("=");
  //If the user input a channel then the default channel is now set
  //If not, we still navigate to the default channel.
  if(pair[0] === "channel" && pair[1] !== ""){
    defaultChannel = pair[1];
  }
}
```

Zdefiniujmy nasze stany z ich wartościami początkowymi. Użyj useState, aby uzyskać gettery i settery dla naszego kanału, upewniając się, że nasz domyślny kanał jest jego wartością początkową. Zrób to samo dla naszej tablicy wiadomości, ale zainicjuj ją pustą tablicą.

Ustawiłem również ogólną nazwę użytkownika dla użytkownika, w oparciu o bieżący czas. Następnie ustaw tymczasowy kanał i zmienną wiadomości na nowy hak, który utworzyliśmy. Proszę bardzo, mamy już skonfigurowane stany dla naszej aplikacji.

```js
const [channel,setChannel] = useState(defaultChannel);
const [messages,setMessages] = useState([]);
const [username,] = useState(['user', new Date().getTime()].join('-'));
const tempChannel = useInput();
const tempMessage = useInput();
```

useEffect w React
-----------------

Następnie możemy użyć nowego, fantazyjnego useEffect, o którym wszyscy mówili. Zasadniczo zastępuje to i reorganizuje wszystkie stare metody cyklu życia, gdy nie używaliśmy haków. Każda funkcja jest uruchamiana przy każdym ponownym renderowaniu, chyba że określimy tablicę zmiennych jako drugi parametr. Za każdym razem, gdy te zmienne ulegną zmianie, funkcja useEffect zostanie ponownie uruchomiona.

_PAMIĘTAJ: Jest to UPROSZCZONE sprawdzanie równości. Liczby i ciągi znaków będą liczone jako różne za każdym razem, gdy ustawisz je jako coś innego, ale useEffect patrzy tylko na wskaźniki obiektów, a nie na ich atrybuty._

Możemy mieć wiele takich funkcji, tylko każdy z ich drugich parametrów musi być inny. Zasadniczo każdy useEffect jest pogrupowany według tego, od czego zależy jego zmiana, więc akcje o podobnych zależnościach działają razem.

```js
useEffect(()=>{
  //Put code we want to run every time these next variables/states change
},[channel, username]);
```

Konfiguracja PubNub w React
---------------------------

Teraz, gdy wiemy już jak działa ten nowy Hook, następnym krokiem jest utworzenie nowego obiektu PubNub! Wyciągnij PubNub, aby pobrać klucze publikowania i subskrypcji, które wygenerowaliśmy wcześniej, i umieść je w nowym obiekcie. Możesz także ustawić identyfikator[UUID](https://www.pubnub.com/docs/react-native-javascript/api-reference-configuration#uuid) dla tego połączenia, niezależnie od tego, czy jest to adres IP, nazwa użytkownika, [wygenerowany identyfikator UUID](https://www.pubnub.com/docs/react-native-javascript/api-reference-configuration#generate-uuid-arg), czy dowolny unikalny identyfikator zdefiniowany przez przypadek użycia. Dla uproszczenia ustawiłem go jako nazwę użytkownika.

```js
const pubnub = new PubNub({
  publishKey: "<ENTER-PUB-KEY-HERE>",
  subscribeKey: "<ENTER-SUB-KEY-HERE>",
  uuid: username
});
```

Po wypełnieniu naszego obiektu informacjami o połączeniu, dołącz my[listener dla zdarzeń PubNub](https://www.pubnub.com/docs/web-javascript/api-reference-publish-and-subscribe#listeners)! Jest to przydatne do wykrywania nowych wiadomości, nowych połączeń lub statusów, a także do obsługi zdarzeń obecności. Nasza aplikacja nie korzysta z obecności ani nie wymaga tworzenia listenera statusu, ale przynajmniej lubię implementować status i rejestrować niektóre wyniki. To, czego naprawdę potrzebujemy dla naszej aplikacji, to możliwość odbierania i obsługi przychodzących wiadomości, więc zdefiniujmy to!

Sprawdź, czy tekst wiadomości ma wartość null lub jest pusty, a jeśli nie, utwórz obiekt newMessage. Ustaw tablicę wiadomości jako jej aktualny stan połączony z nową wiadomością, którą otrzymamy. Funkcja strzałki upewnia się, że używamy bieżącego stanu wiadomości, a nie początkowego stanu renderowania.

```js
pubnub.addListener({
  status: function(statusEvent) {
    if (statusEvent.category === "PNConnectedCategory") {
      console.log("Connected to PubNub!")
    }
  },
  message: function(msg) {
    if(msg.message.text){
      let newMessages = [];
      newMessages.push({
        uuid:msg.message.uuid,
        text: msg.message.text
      });
      setMessages(messages=>messages.concat(newMessages))
    }
  }
});
```

Subskrybowanie kanału w naszym stanie będzie naszym pierwszym połączeniem z serwerem PubNub! Jeśli obecność jest ważna dla twojego przypadku użycia, tutaj możesz ją włączyć. Dowiedz się,kto jest w kanale z Presence[w PubNub React SDK](https://www.pubnub.com/docs/react-native-javascript/api-reference-presence).

```js
pubnub.subscribe({
  channels: [channel]
});
```

Włączenie historii jest kluczową cechą każdego czatu, więc pobierzmy kilka wiadomości, aby utworzyć dziennik czatu. Gdy po raz pierwszy połączymy się z kanałem, użyj funkcji historii, aby pobrać zapisane wiadomości. Użyj odpowiedzi, aby uzyskać dostęp do starych wiadomości i zapisać je w tymczasowej tablicy. Ponieważ nasza tablica powinna być pusta, możemy przenieść te stare wiadomości do naszej pustej tablicy wiadomości.

```js
pubnub.history({
      channel: channel,
      count: 10, // 100 is the default
      stringifiedTimeToken: true // false is the default
}, function (status, response){
  let newMessages = [];
  for (let i  = 0; i < response.messages.length;i++){
    newMessages.push({
      uuid:response.messages[i].entry.uuid ,
      text: response.messages[i].entry.text
    });
  }
  setMessages(messages=>messages.concat(newMessages))
});
```

Kolejną niesamowitą częścią useEffect jest to, że możemy zdefiniować zachowanie, które zamyka wszystko przed ponownym uruchomieniem! Zwróćmy funkcję "cleanup" i wewnątrz, [zrezygnujmy z subskrypcji wszystkich kanałów](https://pubnub.com/developers/chat-resource-center/docs/reference/connecting#disconnecting-from-pubnub) i ustawmy wiadomości na kolejną pustą tablicę.

```js
return function cleanup(){
  pubnub.unsubscribeAll();
  setMessages([]);
}
```

Pub/Sub: Publikowanie
---------------------

Zasubskrybowaliśmy kanał, ale wciąż go nie opublikowaliśmy. W przeciwieństwie do funkcji PubNub w poprzednim useEffect, chcemy publikować, gdy użytkownik wyśle wiadomość. Utwórzmy funkcję o nazwie publishMessage, która będzie publikować wiadomości na naszym kanale.

Utwórz funkcję i sprawdź, czy jest tam coś w naszej tymczasowej wiadomości. Jeśli tak, utwórz obiekt wiadomości! Dołączyłem zarówno wiadomość, jak i nazwę użytkownika, abyśmy wiedzieli, kto ją wysłał, gdy uzyskamy dostęp do wiadomości z dowolnego urządzenia. Zacznij od utworzenia kolejnego obiektu PubNub, dokładnie takiego samego jak poprzedni. Wywołaj na nim polecenie publish, podając jako argument naszą nową wiadomość i kanał.

Po wysłaniu wiadomości wyczyść tymczasowy stan wiadomości. Pozwoli to użytkownikowi na wysłanie kolejnej, jeśli zechce. Nie mamy jeszcze żadnego kodu wywołującego tę funkcję, więc nie zostanie ona uruchomiona, ale następna funkcja, którą zdefiniujemy, już tak!

```js
function publishMessage(){
  if (tempMessage.value) {
    let messageObject = {
      text: tempMessage.value,
      uuid: username
    };
    const pubnub = new PubNub({
      publishKey: "<ENTER-PUB-KEY-HERE>",
      subscribeKey: "<ENTER-SUB-KEY-HERE>",
      uuid: username
    });
    pubnub.publish({
      message: messageObject,
      channel: channel
    });
    tempMessage.setValue('');
  }
}
```

Tworzenie obsługi zdarzeń React
-------------------------------

Ważne jest, abyśmy tworzyli płynne interakcje użytkownika z naszym czatem. Stwórzmy obsługę dla użytkowników, którzy przesyłają wiadomość lub zmieniają kanał za pomocą klawisza "Enter". Utworzymy jedną funkcję, którą nazwałem handleKeyDown, która przyjmuje obiekt zdarzenia.

```js
function handleKeyDown(event){
  //Handling key down event
}
```

Gdy znajdziemy się wewnątrz tej funkcji, naszym celem jest ustalenie, co wywołuje to zdarzenie. Później, gdy utworzymy wejścia, ustawimy dla nich identyfikatory. Zacznijmy od sprawdzenia identyfikatora celu zdarzenia. Jeśli jest to "messageInput", sprawdź jeszcze raz, czy naciśnięty klawisz to "Enter", czy nie. Jeśli tak, wywołaj naszą funkcję publishMessage.

```js
if(event.target.id === "messageInput"){
  if (event.key === 'Enter') {
    publishMessage();
  }
}
```

Wykonaj te same kontrole, aby rozpocząć tę instrukcję else if, co poprzednio, ale tym razem używając "channelInput" jako identyfikatora. Utwórz stałą wartość, która będzie przechowywać nasz tymczasowy kanał, ale pamiętaj, aby przyciąć wszelkie początkowe lub końcowe białe znaki. Gdybyśmy wywoływali tutaj tylko setChannel, nie musielibyśmy sprawdzać, czy nowy i stary kanał są takie same.

Ponieważ zmieniamy również bieżący adres URL na ten, który utworzyliśmy, potrzebujemy sprawdzenia, ponieważ wystąpiłyby niepotrzebne duplikaty. Utworzenie nowego ciągu URL, który zawiera nazwę nowego kanału, pozwala również użytkownikom na łatwiejsze udostępnianie linków do stron. Na koniec ustaw stan naszego tymczasowego kanału na pusty ciąg znaków.

```js
else if(event.target.id === "channelInput"){
  if (event.key === 'Enter') {
    //Navigates to new channels
    const newChannel = tempChannel.value.trim()
    if(newChannel){
      if(channel !== newChannel){
        //If the user isnt trying to navigate to the same channel theyre on
        setChannel(newChannel);
        let newURL = window.location.origin + "?channel=" + newChannel;
        window.history.pushState(null, '',newURL);
        tempChannel.setValue('');
      }
    }
  //What if there was nothing in newChannel?
}
```

Jest to świetne rozwiązanie, jeśli użytkownik wprowadzi kanał do naszych danych wejściowych, ale co, jeśli tego nie zrobi? Możemy albo ostrzec ich o błędzie, pozostać na tym samym kanale, albo przenieść ich do wybranego przez nas kanału domyślnego. Wybrałem ostatnią opcję, aby przenieść ich do "Global". Wykonaj to samo sprawdzenie, co poprzednio, ale tym razem użyj "Global", a następnie ustaw kanał jako ten.

Tworzymy nowy adres URL i przesyłamy go do historii strony, tak jak poprzednio, ale bez żadnych parametrów. Kod, który umieściliśmy na początku naszej aplikacji, rozpozna to i użyje domyślnego kanału. Ponownie ustawiamy kanał tymczasowy na pusty ciąg znaków, upewniając się, że umieściliśmy ten fragment kodu przed ostatnim kończącym nawiasem klamrowym.

```js
else{
  //If the user didnt put anything into the channel Input
  if(channel !== "Global"){
    //If the user isnt trying to navigate to the same channel theyre on
    setChannel("Global");
    let newURL = window.location.origin;
    window.history.pushState(null, '',newURL);
    tempChannel.setValue('');
  }
}
```

Dodajemy bieżący adres URL do historii przycisku wstecz naszej przeglądarki, aby dać naszym użytkownikom możliwość przejścia do poprzednich kanałów za jego pośrednictwem. Aby nasz czat mógł faktycznie nawigować między poprzednimi kanałami za pomocą przycisku wstecz, musimy zrobić jeszcze kilka rzeczy.

Nawigacja między poprzednimi kanałami
-------------------------------------

Teraz, gdy skonfigurowaliśmy wszystkie funkcje naszego czatu React, dodajmy funkcję ponownego renderowania naszej strony. Będziemy zmieniać nasz stan, zamiast przeładowywać, gdy użytkownik kliknie wstecz lub do przodu między naszymi stronami.

Utwórz funkcję o nazwie goBack, która sprawdza adres URL kanału i ustawia "Globalny" lub znaleziony kanał dla naszego stanu kanału. Ta funkcja nie zostanie uruchomiona, jeśli nie dodamy detektorów zdarzeń do naszej strony!

```js
function goBack() {
  //Access the parameters provided in the URL
  let query = window.location.search.substring(1);
  if(!query){
    setChannel("Global")
  }else{
    let params = query.split("&");
    for(let i = 0; i < params.length;i++){
      var pair = params[i].split("=");
      //If the user input a channel then the default channel is now set
      //If not, we still navigate to the default channel.
      if(pair[0] === "channel" && pair[1] !== ""){
          setChannel(pair[1])
      }
    }
  }
}
```

Chcemy dodać słuchacza tylko po załadowaniu strony i usunąć go, gdy ją opuścimy. To brzmi jak kolejne zastosowanie dla haka useEffect! Utwórz kolejny, ale jako drugi argument przekaż pustą tablicę. Teraz działa to tylko raz przy początkowym ładowaniu naszego czatu. Nie będzie uruchamiany przy każdym ponownym renderowaniu.

Utwórz detektor zdarzeń na naszym "oknie" i zwróć funkcję czyszczącą, która usunie ten detektor. Słuchacz zdarzeń będzie czekał na "popstate", czyli kliknięcie przez użytkownika przycisku wstecz/do przodu w przeglądarce. Umieść ostatnią utworzoną przez nas funkcję, "goBack", po nazwie zdarzenia. Teraz nasza strona nie będzie się przeładowywać, ale będzie renderować to, czego potrzebuje, kiedy tego potrzebuje!

```js
useEffect(() => {
  window.addEventListener("popstate",goBack);
  return function cleanup(){
    window.removeEventListener("popstate",goBack);
  }
},[]);
```

Używanie JSX do tworzenia React UI
----------------------------------

Teraz, gdy ukończyliśmy całą logikę, której potrzebujemy w naszym backendzie, zbudujmy prosty, ale nowoczesny front-end! Aby to zrobić, zwracamy [JSX](https://reactjs.org/docs/introducing-jsx.html), język opisu interfejsu użytkownika JavaScript. Pozwala nam on na używanie własnych zmiennych i obiektów wewnątrz grup zwanych komponentami. Składnia wygląda podobnie do HTML z silnikiem szablonów, ale to JSX!

Gdy zmienna/stan ulegnie zmianie, każdy komponent, który jej używa, zostanie ponownie wyrenderowany z nową wartością. To właśnie sprawia, że nasza aplikacja jest bardziej responsywna, gdy tylko nastąpi zmiana, zostanie zaktualizowana. Z tego powodu używanie PubNub i React razem jest świetnym pomysłem. PubNub jest w stanie szybko dostarczać wiadomości, a React nadąża, aktualizując swoje komponenty!

### Projektowanie aplikacji

Stwórzmy teraz nasz projekt komponentu aplikacji. Material-UI zapewnia nam piękne komponenty, które możemy wykorzystać i wypełnić własnymi informacjami. Skorzystaj z poniższego projektu, a my omówimy, jakie funkcje są wywoływane w niektórych obszarach.

```js
return(
  <Card >
    <CardContent>
      <div className="top">
        <Typography variant="h4" inline >
          PubNub React Chat
          </Typography>
        <Input
          style={{width:'100px'}}
          className="channel"
          id="channelInput"
          onKeyDown={handleKeyDown}
          placeholder ={channel}
          onChange = {tempChannel.onChange}
          value={tempChannel.value}
        />
      </div>
      <div >
        <Log messages={messages}/>
      </div>
    </CardContent>
    <CardActions>
      <Input
        placeholder="Enter a message"
        fullWidth={true}
        id="messageInput"
        value={tempMessage.value}
        onChange={tempMessage.onChange}
        onKeyDown={handleKeyDown}
        inputProps={{'aria-label': 'Message Field',}}
        autoFocus={true}
      />
      <Button
        size="small"
        color="primary"
        onClick={publishMessage}
        >
        Submit
      </Button>
    </CardActions>
  </Card>
);
```

Może się wydawać, że jest tu dużo projektu, ale organizuje on kilka odrębnych elementów.

Najpierw mamy nasz tytuł wewnątrz komponentu Typography. Następnie w tym samym elemencie div znajduje się nasz kanał Input. Wejścia zawierają wiele właściwości, które definiują działania, jakie mogą podjąć. Obejmują one jego identyfikator, funkcję obsługującą onKeyDown, jego symbol zastępczy, funkcję onChange i jego wartość.

Posiada również obszary do odwoływania się do swoich stylów. Po tym divie mamy nasz Log, kolejny funkcjonalny komponent, którego jeszcze nie stworzyliśmy. Ten dziennik pobiera naszą tablicę wiadomości i będzie renderowany za każdym razem, gdy ta tablica się zmieni. Po naszym dzienniku możemy mieć kolejne wejście i przycisk. Input to miejsce, w którym użytkownik tworzy wiadomość. Wypełniamy jego właściwości odpowiednimi stanami i zmiennymi, których dotyczy.

Ustawiamy również autofokus. Ustawiamy onClick przycisku na naszą funkcję publikowania wiadomości, aby umożliwić użytkownikom inny sposób wysyłania wiadomości. To koniec naszego komponentu App, a back-end został ukończony. Następnie musimy utworzyć jeszcze dwa małe komponenty do wyświetlania naszych wiadomości.

### Projektowanie dziennika i wiadomości

Nasza aplikacja definiuje większość tego, jak działa nasz czat, ale potrzebujemy jeszcze dwóch komponentów, aby go uzupełnić. Oba zwracają JSX i organizują sposób wyświetlania naszych wiadomości. Pierwszy z nich, Log, wyświetla listę elementów ListItems wypełnionych typografią. Te ListItems iterują po mapie naszych wiadomości i wyświetlają Message. Tworzymy Message z kluczem indeksu w tablicy, uuid wiadomości i tekstem wiadomości.

```js
function Log(props) {
  return(
    <List component="nav">
      <ListItem>
      <Typography component="div">
        { props.messages.map((item, index)=>(
          <Message key={index} uuid={item.uuid} text={item.text}/>
        )) }
      </Typography>
      </ListItem>
    </List>
  )
};
```

Komponent Message reprezentuje pojedynczą wiadomość, element div, wypełniony uuid i tekstem, oddzielone dwukropkiem. Dzieci naszego komponentu App uzyskują dostęp do wiadomości za pomocą rekwizytów. Nie mogą edytować ani zmieniać, a jedynie czytać i wyświetlać to, co zostało im przekazane.

Teraz, gdy zakończyliśmy definiowanie naszych komponentów, kończymy naszą aplikację, eksportując ją na dole naszego pliku. Kod w index.js wyrenderuje naszą aplikację na stronie internetowej!Uruchom

```js
npm start
```

w naszym folderze projektu i przejdź do [localhost:3000](localhost:3000) w naszej przeglądarce, aby zobaczyć naszą aplikację uruchomioną!

```js
function Message(props){
  return (
    <div >
      { props.uuid }: { props.text }
    </div>
  );
}
export default App;
```

Oto gif czatu w akcji:

[![react hooks chat gif](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jkx/cadaa09d1dbce7a6f13e1fce08cc4a30/react-hooks-chat.gif)](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jkx/cadaa09d1dbce7a6f13e1fce08cc4a30/react-hooks-chat.gif)

Udało nam się stworzyć aplikację, która pozwala użytkownikom czatować w wybranych przez siebie kanałach. Pełne [repozytorium kodu również tutaj](https://github.com/PubNubDevelopers/ReactHooksChat.PubNub).

Co dalej?
---------

Teraz, gdy masz już zaimplementowaną podstawową funkcjonalność przesyłania wiadomości, nadszedł czas, aby dodać więcej funkcji! Udaj się na naszą stronę z [rozwiązaniami](https://www.pubnub.com/solutions/chat/) dla czatu, aby zapoznać się z nowymi samouczkami, najlepszymi praktykami i wzorcami projektowymi, aby przenieść swoją aplikację czatu na wyższy poziom.

  
**Jeśli osadzona zawartość nie jest dostępna** na tej stronie, można ją również wyświetlić pod adresem [https://pubsub-quickstart-app.pubnub.com/signup](https://pubsub-quickstart-app.pubnub.com/signup).

#### Zawartość

[Pub/Sub i pobieranie](#h-0)[historiiPoczątekJak](#h-1) zainstalować[React.js i PubNubDlaczego](#h-2) warto[korzystać z React Hooks?](#h-3)[Tworzenie własnych React HooksProjektowanie](#h-4)[komponentów ReactUstawianie](#h-5)[komponentu App Component: Stan za pomocą React HooksUżycie Effect](#h-6)[w ReactUstawianie](#h-7) PubNub[w ReactPub/Sub](#h-8)[: PublikowanieTworzenie](#h-9)[React Event HandlersNawigacja](#h-10)[pomiędzy poprzednimi kanałamiUżycie](#h-11)[JSX do stworzenia React UIApp](#h-12)[DesignLog](#h-13)[i Message DesignCo](#h-14)[dalej?](#h-15)

Jak PubNub może ci pomóc?
=========================

Ten artykuł został pierwotnie opublikowany na [PubNub.com](https://www.pubnub.com/blog/creating-a-chat-window-using-react-and-hooks/)

Nasza platforma pomaga programistom tworzyć, dostarczać i zarządzać interaktywnością w czasie rzeczywistym dla aplikacji internetowych, aplikacji mobilnych i urządzeń IoT.

Fundamentem naszej platformy jest największa w branży i najbardziej skalowalna sieć przesyłania wiadomości w czasie rzeczywistym. Dzięki ponad 15 punktom obecności na całym świecie obsługującym 800 milionów aktywnych użytkowników miesięcznie i niezawodności na poziomie 99,999%, nigdy nie będziesz musiał martwić się o przestoje, limity współbieżności lub jakiekolwiek opóźnienia spowodowane skokami ruchu.

Poznaj PubNub
-------------

Sprawdź [Live Tour](https://www.pubnub.com/tour/introduction/), aby zrozumieć podstawowe koncepcje każdej aplikacji opartej na PubNub w mniej niż 5 minut.

Rozpocznij konfigurację
-----------------------

Załóż [konto](https://admin.pubnub.com/signup/) PubNub, aby uzyskać natychmiastowy i bezpłatny dostęp do kluczy PubNub.

Rozpocznij
----------

[Dokumenty](https://www.pubnub.com/docs) PubNub pozwolą Ci rozpocząć pracę, niezależnie od przypadku użycia lub [zestawu SDK](https://www.pubnub.com/docs).