React: Local state management with Apollo

Table of Content

Базовими речами в React є props та state, це ключові моменти, які потрібно зрозуміти і розібрати.

З props все абсолютно просто – в них передаємо дані на основі яких компоненти промальовуються. Props – це просто контейнер для зберігання даних на рівні компоненту, якщо змінити дані в props, то з компонентом нічого не відбудеться. Геть інша роль відведена для state, якщо змінити state, зараз же запускається перемальовування компоненту. Але потрібно чітко усвідомити, що state можна змінювати тільки через this.setState(), інакше компонент не перемалюється і можливі помилки.

State здебільшого використовується при виникнені події, як то onClick, onSelect, onChange, onSelectRow і т.д. Коли якась подія викликається, в ній можна змінити state компоненту через this.setState(), що в свою черегу запускає перемальовування компоненту.

Є гарна стаття “8 things to learn in React before using Redux“. Спокійно замініть Redux на будь який інший менеджер керування станом (Apollo, MobX), суть статті від того не зміниться, там лише теорія з мінімальними прикладами на React.

State який пропонує React з коробки, досить гарно працює на малих компонентах, зміна стану який впливає лише на них або на найближчих сусідніх компонетів. Але коли зміна стану одного компонету впливає на десяток інших, і потрібно передавати state callback від спільного батька для всіх компонетів в низ по дочірніх компонентах, тоді це стає головним болем розробника з яким складно боротись. Кажучи правду, таке трапляться на середніх і великих проектах, тому відмовлятись від стандартного this.setState() в жодному разі не можна, потрібно лише навчитись це правильно готувати.

Для тих хто працював з Redux, буде корисне наступне твердження Mutations acts kinda like reducers in redux and changes the state. Для інших це твердження теж буде корисне, тому що саме Mutations змінюють стан.

При використанні Apollo та його apollo-link-state зміна локального стану this.setState() зміщується на більш вищий (глобальний) рівень, і тепер стан компоненту(ів) змінюється при виклику cache.writeData(), cache.writeQuery() та cache.writeFragment() в Mutation – це основний момент який потрібно чітко усвідомити. Найкраще починати вивчення з офіційної документації, Local state management та Manage your local data with Apollo Client, після цього обов’язкова до прочитання A apollo-link-state Tutorial for Local State in React

Важлива вирізка з документації:

Updates to Apollo Client state via apollo-link-state will also automatically update any components using that data in a query.

Навіть після того коли вище наведена інформація здається зрозумілою, залишається питання: “Як все ж змусити працювати local state в парі з даними із сервера?”. Відповідь проста, атрибут update який передаємо в Mutation як props. Детально все розписано в Learn how to update data with Mutation components.

Sometimes when you perform a mutation, your GraphQL server and your Apollo cache become out of sync. This happens when the update you’re performing depends on data that is already in the cache; for example, deleting and adding items to a list. We need a way to tell Apollo Client to update the query for the list of items. This is where the update function comes in!

Початківцям слід бути особливо уважними з деструктуризацією. Наступні два методи однакові, але ключова відмінність на 16 стрічці в другому прикладі може зламати всі намагання розібратись з Local State.

switchMarketplace: (_, {id, name}, {cache}) => {
  const query = gql`
    query GetCurrentMarketplace {
      currentMarketplace @client {
        id
        name
      }
    }
  `;

  const previous = cache.readQuery({query});
  const data = {
    currentMarketplace: {
      ...previous.currentMarketplace,
      id,
      name
    }
  };

  // you can also do cache.writeData({ data }) here if you prefer
  cache.writeQuery({query, data});

  return null;
}
switchMarketplace: (_, variables, {cache, getCacheKey}) => {
  const query = gql`
    query GetCurrentMarketplace {
      currentMarketplace @client {
        id
        name
      }
    }
  `;

  const previous = cache.readQuery({query});
  const marketplace = {id: variables.id, name: variables.name};
  const data = {
    currentMarketplace: {
      ...previous.currentMarketplace,
      marketplace // it will not work
    }
  };

  // you can also do cache.writeData({ data }) here if you prefer
  cache.writeQuery({query, data});

  return null;
}

Обов’язково до перегляду відео де авторка на простому прикладі пояснює як працює Apollo Local State, під відео є посилання на github і demo версію.

За посиланням розміщений fork з простим прикладом реалізації Switcher компоненту, який підійде для будь якого інтерфейсу, де при зміні глобального параметру має перемальовуватись інтерфейс, будь то мультимовність, чи перемикач маркеплейсів або будь що інше.

Leave a Reply

Your email address will not be published. Required fields are marked *