source: https://unsplash.com/
Metoda mockup'u - mój sposób na pisanie czystszego kodu.
category: other |published: 2021-06-24
<Quick.Webdev />
be in touch with web development
Reading time: 6 minutes
W świecie Javascriptu istnieje mnóstwo frameworków i bibliotek do budowania aplikacji webowych. Najpopularniejszą technologią na frontendzie jest React, a po stronie serwera - Express, Koa czy Nest.js. Podczas budowania aplikacji fullstackowej ważne jest, aby zaplanować dobrze architekturę, strukturę katalogów i sposów przepływu danych w obrębie naszej aplikacji. W tym artykule przedstawię moje podejścia do problemu jakim jest komunikacja między tymi dwoma światami z użyciem tradycyjnego REST API.
Jako przykład, chciałbym przedstawić kilka części mojej aplikacji z quizami którą tworzyłem przez ostatnie miesiące. Kliknij, by przejść do projektu tutaj
W komponencie dashboard mamy listę z quizami stworzonymi przez użytkowników. Aby odczytać informacje o tych quizach musimy wykonać zapytanie do naszego API. Właśnie tutaj zaczyna się cała komunikacja.
Przejdź do => /src/pages/Dashboard/index.js
const Dashboard = () => {
const { data: quizzes, loading, error } = useFetching(getQuizzes);
if (loading) return <Loader />;
if (error) return <ErrorPage msg={error} />;
return (
<Layout>
...W linii drugiej wywołuje własny hook o nazwie useFetching z argumentem getQuizzes. Ten argument to referencja do funkcji w pliku /src/api.index.js. Zobaczmy jak ta funkcja wygląda a następnie pokażę co dzieje się w hooku useFetching.
export const getQuizzes = async () => {
const { data } = await instance.get('/api/quizzes').catch(({ response }) => response);
return data;
};Jest to zwykła asynchroniczna funkcja, która wysyła zapytanie do ścieżki /api/quizzes używając paczki axios. Używam również metody catch aby wyłapać potencjalne błędy. Wszystkie informacje znajdują się we właściwości data, więc destrukturyzuje je używając składni ES6.
Przejdź do => /src/hooks/useFetching.js
export const useFetching = (method, ...methodArgs) => {
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [data, setData] = useState(undefined);
useEffect(() => {
const cancelToken = axios.CancelToken;
const source = cancelToken.source();
(async () => {
const { type, data, msg } = await method([...methodArgs]);
if (type === responseTypes.success) {
setData(data);
} else {
setError(msg);
}
setLoading(false);
})();
return () => source.cancel();
}, []);
return { data, loading, error };
};useFetching to nic innego jak funkcja, która jako parametr przyjmuje referencję do funkcji, którą ma wywołać oraz tablicę opcjonalnych parametrów, które ta funkcja przyjmuje. Poniżej deklaruję stan (loading, error i data). W linii 10 wywołuję przekazaną jako parametr funkcję z argumentami używając spread operatora i wtedy desktrukturyzuję response, data i wiadomość z błędem (tutaj to wartość o nazwie msg). Potem, jeżeli zapytanie zakończyło się pomyślnie ustawiam zmienną data, error i wartość zmiennej loading na false aby dać znak, że żądanie się zakończyło, a komponent loader może zniknąć. Pod koniec zwracam obiekt z niezbędnymi danymi do wyświetlenia w komponencie. Nie zapominaj by zakończyć wszyskie aktywne subskrypcje i zapytania asynchroniczne w funkcji czyszczącej komponent (cleanup function). Ja to robię używając accessTokena, który daje nam paczka axios. Teraz, wróćmy do naszego komponentu Dashboard.
const { data: quizzes, loading, error } = useFetching(getQuizzes);Tutaj destrukturyzuję zwrócony obiekt z hooka, a następnie używam tych danych do zwizualizowania naszego stanu w UI.
if (loading) return <Loader />;
if (error) return <ErrorPage msg={error} />;I na końcu iterujemę po tablicy z quizami.
Przejdźmy teraz do backendu, aby zobaczyć w jaki sposób nasze zapytanie jest obsługiwane.
Przejdź do => /routes/api.js
router.get("/quizzes", verify, quizzesController.getQuizzes);W tej linii tworzę ścieżkę GET /quizzes która obsługuje zapytanie. Teraz zapytanie jest przekazywane do dedykowanego kontrolera.
Rolą kontrolerów jest:
Właśnie to dzieję się w pliku /controllers/quizzes.js.
module.exports.quizzesController = {
getQuizzes: async (req, res) => {
if (req.user) {
const { type, data, msg } = await QuizzesService.getQuizzes();
if (type === responseTypes.success) {
res.status(200).json({ type, data });
} else {
res.status(401).json({ type, msg });
}
}
},
...Tutaj mamy metodę getQuizzes, która spełnia wyżej wymienione reguły:
Rolą serwisów jest obsługa bardziej zaawansowanych i czasochłonnych zadań takich jak wykonywanie zapytań do bazy danych, wykonywanie obliczeń, czy przygotowywanie gotowego obiektu do odesłania kontrolerowi.
class QuizzesService {
async getQuizzes() {
try {
const quizzes = await Quiz.find({}).sort({ creationDate: -1 });
if (quizzes.length > 0) {
return {
type: responseTypes.success,
data: quizzes,
};
} else throw messages.QUIZZES_NOT_FOUND;
} catch (e) {
return makeResponse(e, responseTypes.error);
}
}
...W ostatnim kroku, wykonuję zapytanie do MongoDB. Dostaję wszystkie quizy, i sortuję je według daty publikacji. Jeżeli quizy istnieją, zwraca je - w przeciwnym przypadku wyłapuję błąd i odsyłam odpowiedź.
W tym miejscu polecam Ci używać składni try catch aby Twój kod był bardziej czytelny i łatwy do debugowania.
Voila! Nasza komunikacja właśnie dobiegła końca. Teraz, dane zwrócone z Service'u odsyłamy kontrolerowi, a następinie na część frontendową. Następnie rozwiązywana zostaje funkcja w api, hooku useFetching i stamtąd trafia do odpowiedniego Reacowego komponentu, gdzie zaczęła się cała długa, ale fajna podróż! 😎
Podsumowując, tak wygląda komunikacja krok po kroku:
Komponent Reactowy -> hook useFetching -> metoda w API -> ścieżka na backend -> kontroler -> Service (tutaj mamy nasze dane) -> kontroler -> metoda API -> hook useFetching -> komponent Reactowy (korzystamy z danych).
Other articles:
source: https://unsplash.com/
Metoda mockup'u - mój sposób na pisanie czystszego kodu.
category: other |published: 2021-06-24
source: https://unsplash.com/
The mockup method – my way to write cleaner code.
category: other |published: 2021-06-23
source: https://unsplash.com/
Dlaczego nie musisz perfekcyjnie znać ES6+ przed nauką Reacta?
category: frontend | other |published: 2021-06-05
source: https://unsplash.com/
Why you don’t have to know ES6+ perfectly before learning React?
category: other | frontend |published: 2021-06-04
source: https://unsplash.com/
Komunikacja frontend-backend w React, Express i REST API - moje podejście.
category: frontend | backend |published: 2021-06-02
source: https://unsplash.com/
How to cope with frontend-backend communication using React, Express and REST API?
category: backend | frontend |published: 2021-06-01
source: https://unsplash.com/
Hymn do testera Kuby
category: other |published: 2021-01-26
source: https://unsplash.com/
Hello world!
category: frontend | other |published: 2021-01-23