Русский
Русский
English
Статистика
Реклама

Соединяем Redux и GraphQL на простом примере

Попробуем соединить Redux и GraphQL без использования Apollo Client или Relay.

Что такое Redux

Редакс это архитектурный подход, который реализован в виде небольшой библиотеки. Он предполагает, что у приложения есть хранилище данных state. Изменять хранилище state напрямую нельзя. Это можно сделать только через вспомогательные функции reducers.

Псевдокод:

function dispatch(action) {    state = reducer(state, action);}

Для соединения реакта и редакса используется библиотека react-redux. Она позволяет получать данные из state внутри компонентов и инициировать их обновление через dispatch.

Что такое GraphQL

GraphQL для клиента это просто POST-запрос с особым форматом body:

REST

GraphQL

GET /books/id

POST /graphql
query{ book(id) {} }

POST /books
{}

POST /graphql
mutation{ addBook() {...} }

UPDATE /books/id
{}

POST /graphql
mutation{ updateBook(id) {...} }

DELETE /books/id

POST /graphql
mutation{ deleteBook(id) {} }

GraphQL без Apollo Client (и Relay)

Apollo-client это самая популярная библиотека для работы с GraphQL. Она предоставляет интерфейс для работы с запросами внутри компонентов, а также решает задачу хранения кэша. Вместо Redux предполагается использовать внутренние механизмы. Однако эти механизмы далеко не такие простые и удобные.

Вместо Apollo Client для примера воспользуемся такой функцией:

const graphqlAPI = (query, variables) => fetch("/graphql", {    method: "POST",    body: JSON.stringify({ query, variables })});

redux-toolkit

Я буду использовать официальный набор утилит от redux redux-toolkit. Они решают самую частую претензию к редаксу бесконечное количество шаблонного кода. В этот набор входит:

  • createEntityAdapter для упрощения работы с редьюсерами и селекторами.

  • createAsyncThunk для упрощения работы с сайд-эффектами и API.

  • createSlice для упрощения работы с actions и разрешения мутабельности.

Пример

Представим простое приложение, которое запрашивает список книг с сервера и выводит их.

// booksSlice.jsimport {  createEntityAdapter,  createAsyncThunk,  createSlice} from "@reduxjs/toolkit";// Наш редьюсер будет хранить список книг.// createEntityAdapter генерирует готовый набор функций// для добавления, обновления и удаления книг внутри редьюсера// (addOne, addMany, updateOne, removeOne, setAll, ...), const books = createEntityAdapter();// createAsyncThunk позволяет работать с асинхронным кодом.// Например, с запросами к API.// getBooks работает как набор actions, которые можно диспатчить в приложении.export const getBooks = createAsyncThunk("get books", async () =>   await graphqlAPI(`    query {      books  {        id        title      }    }  `));export const addBook = createAsyncThunk("add book", ({ title }) =>  graphqlAPI(`    mutation ($title: string!){      add_book(objects: { title: $title }) {        id        title      }    }  `, { title }));// createSlice  обертка над createAction и createReducer.// Она позволяет работать со стейтом мутабильно.export const booksSlice = createSlice({  name: "books",  initialState: books.getInitialState(),  extraReducers: {    // Работаем с результатом запроса getBooks    [getBooks.fulfilled]: (state, action) => {      // setAll автоматически создан в createEntityAdapter      books.setAll(state, action.payload);    },    // Работаем с результатом запроса addBook    [addBook.fulfilled]: (state, action) => {      // addOne автоматически создан в createEntityAdapter      books.addOne(state, action.payload);    },  },});// createEntityAdapter генерирует набор готовых селекторов// (selectIds, selectById, selectAll, ...)export const booksSelectors = books.getSelectors((s) => s.books);export default booksSlice.reducer;
// index.jsimport { useDispatch, useSelector } from "react-redux";import { getBooks, addBook, booksSelectors } from "./booksSlice";export function Books() {  const dispatch = useDispatch();  // booksSelectors.selectAll втоматически создан через createEntityAdapter  const books = useSelector(booksSelectors.selectAll);   useEffect(() => {    dispatch(getBooks());  }, [dispatch]);  return (    <div>      <button onClick={() => dispatch(addBook({ title: "New Book" }))}>        Add book      </button>      <ul>        {books.map((b) => <li key={b.id}>{b.title}</li>)}      </ul>    </div>  );}

Что дальше

Поэкспериментировать с Redux можно локально.
Для настройки окружения достаточно одной команды:
npx create-react-app my-app --template redux

Для Typescript:
npx create-react-app my-app --template redux-typescript

Вместо fetch можно воспользоваться библиотекой graphql-request.

Создать бэкенд на GraphQL можно без написания кода.
Для этого подходят такие проекты как hasura или prisma.

Источник: habr.com
К списку статей
Опубликовано: 19.10.2020 12:14:37
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Разработка веб-сайтов

Javascript

Api

Reactjs

Redux

React

Graphql

React-redux

Example

Пример

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru