Использование React Context API

Давайте использовать React Context API, чтобы изменить тему в программе!

zmp2k4r128poj1gsws61

Но сначала некоторые контекст! ?

Ладно, в стороне ужасающие каламбуры, давайте посмотрим, для чего предназначен React Context API и что он делает. Есть отличная строка из документов React…

Контекст обеспечивает способ передачи данных через дерево компонент без необходимости передавать реквизиты вручную на каждом уровне.

Или другими словами, вы можете использовать React Context API, чтобы избежать сверления, если вам нужна более подробная концепция, просмотрите предоставленные ссылки.

Ранее я рассматривал внедрение React Context API в своем блоге Gatsby, который я задокументировал, когда это делал; вы можете увидеть, как это было здесь.

Объясните мне контекстный API.

Отличный ресурс для объяснения API можно найти в @leighchalliday с отличным примером использования на эту тему.

что мы делаем…

В этой публикации мы собираемся расширить пример, созданный для начала работы со стилизованными компонентами, поскольку он содержит большинство кода, который нам понадобится, чтобы начать работу с React Context API.

Мы собираемся расширить этот пример для управления состоянием темы прикладной программы.

Итак, подытоживая:

  • Создайте базовую программу CreateReact
  • Использовать styled-components? для укладки
  • Добавьте темы для переключения с помощью React Context API
  • Используйте React Context API!

Что нам понадобится…

Все, что нам нужно, это подключение к Интернету и современный веб-браузер! Потому что мы собираемся делать все это онлайн в великолепной CodeSandbox!

Если у вас есть аккаунт GitHub или нет, CodeSandbox позволит вам немедленно начать кодирование!

Версии:

Данное руководство используется следующими версиями зависимостей.

  • реагировать: 16.4.2
  • react-dom: 16.4.2
  • реагировать-скрипты: 1.1.4
  • styled-components: 3.4.5

Давайте начнем

Давайте снова рассмотрим тему базовой программы для создания реакции, на этот раз вместо того, чтобы добавлять состояние к компоненту, мы будем использовать React Context API для управления состоянием. Найдутся люди, которые будут утверждать, что это несколько лишнее для переключения темы, но это приведено в пример того, когда использовать Context API в документации React, поэтому я позволю вам определиться с действительностью этого пункта. Для этого примера, я надеюсь, он даст вам более ясное представление о том, как использовать Context API в программе.

Зависимости

Откройте React CodeSandbox и добавьте styled-components как зависимость:

d49drafvtvz3ws2br9vs

Структура файла

Другой областью для велосипедных сайдов является структура файлов, в этом сценарии мы добавляем папки для components, contexts и theme пожалуйста, не стесняйтесь структурировать свои файлы так, как считаете нужным, вот как мы это сделаем для этого примера ❤️

Добавьте каталоги в src папку, чтобы мы могли добавить некоторые компоненты, структура файла должна выглядеть примерно так:

context-demo/
├─ public/
├─ src/
│  └─ components/
│  └─ contexts/
│  └─ theme/
└─ package.json

Создайте базовую программу Create React

Хорошо, что мы собираемся сделать, это добавить в App.js компонент к components папку, затем используйте ее в папке src/index.js файл.

The App.js компонент может быть функциональным компонентом без состояния, как в этом примере, поскольку мы собираемся обрабатывать состояние с помощью Context API.

Здесь вы можете увидеть мой схематический ввод, когда я создаю каталоги и добавляю файлы App.js компонент.

oyxpggt00q754iv1azp0

Затем мы можем удалить style.css файл и ссылка в src/index.js как мы будем создавать стили с помощью styled-components? а затем воспользуйтесь нашим App.js компонент:

yyne3q36jc0zca2ld89u

Хорошо, причина, почему я абстрагировал App.js компонент из src/index.js файл так, что когда мы переходим к использованию Context API, мы можем добавить его на самый высокий уровень в нашем приложении, т.е. src/index.js.

А что с остальными?

Итак, это на самом деле не программа Create React, поскольку мы используем CodeSandbox, я просмотрел основные стили, используемые в сообщении о начале работы со стилизованными компонентами, поэтому пора обратиться к нему, чтобы имитировать нужные нам стили.

Это означает, что мы собираемся делать, вместо того чтобы углубляться в стиль каждого из компонентов, составляющих базовый внешний вид программы Create React, мы собираемся повторно использовать компоненты, поэтому будет немного копировального вставки задействовано сейчас.

Шаблонный код программы Create React содержит один файл, стиль которого мы рассматриваем в посте для начала работы со стилизованными компонентами, который есть App.js файл, другие остаются или удаляются, основной стиль App.js есть:

App.css

.App {
  text-align: center;
}

.App-logo {
  animation: App-logo-spin infinite 20s linear;
  height: 80px;
}

.App-header {
  background-color: #222;
  height: 150px;
  padding: 20px;
  color: white;
}

.App-title {
  font-size: 1.5em;
}

.App-intro {
  font-size: large;
}

@keyframes App-logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

Используйте стилизованные компоненты для стилизации

Теперь мы собираемся воспроизвести стили из App.css файл со стилизованными компонентами, давайте перечислим их здесь и рассмотрим их:

AppWrapper
AppHeader
AppTitle
rotate360
AppLogo
# We're adding our own styles for
AppIntro
Underline
StyledHyperLink
Button

AppWrapper это обертка верхнего уровня, которая в большем компоненте может использоваться для компоновки с помощью CSS Grid или Flexbox, в нашем случае мы собираемся выровнять центр текста.

uc08zkkf4ay1hq8pkt3w

Достаточно просто, не правда ли? Теперь большинство остальных компонентов будут использовать styled-components ThemeProvider это то, к чему мы собираемся передать нашу тему из Context API.

Добавьте темы для переключения с помощью React Context API

Ладно, нам нужно определить некоторые темы для передачи ThemeProviderмы определим несколько аспектов темы, которые мы хотим изменить, а именно:

primary; // colour
secondary; // colour
danger; // colour
fontHeader; // font
fontBody; // font

Создайте файл, содержащий объект темы в theme каталог и назовите его globalStyle.js и добавить следующее:

import { injectGlobal } from 'styled-components';

export const themes = {
  theme1: {
    primary: '#ff0198',
    secondary: '#01c1d6',
    danger: '#e50000',
    fontHeader: 'Old Standard TT, sans, sans-serif',
    fontBody: 'Nunito, sans-serif',
  },

  theme2: {
    primary: '#6e27c5',
    secondary: '#ffb617',
    danger: '#ff1919',
    fontHeader: 'Enriqueta, sans-serif',
    fontBody: 'Exo 2, sans, sans-serif',
  },

  theme3: {
    primary: '#f16623',
    secondary: '#2e2e86',
    danger: '#cc0000',
    fontHeader: 'Kaushan Script, sans, sans-serif',
    fontBody: 'Headland One, sans-serif',
  },
};

injectGlobal`
  @import url('
    
    Old+Standard+TT:400,700|
    Nunito:400,700'|
    Enriqueta:400,700|
    Exo+2:400,700|
    Kaushan+Script:400,700|
    Headland+One:400,700|
  ');

  body {
    padding: 0;
    margin: 0;
  }
`;
qnxbteccbaw92jbwsq9c

Ладно, так что ничего на самом деле не происходит, кроме настройки стилей для использования позже.

Вы это заметите injectGlobal здесь используется, здесь мы устанавливаем шрифты для использования во всей программе, injectGlobal следует использовать один раз в программе, чтобы установить такие глобальные стили.

Вперед! Давайте теперь сосредоточимся на внесении основных стилей программы App.js компонент. Теперь мы можем начать использовать ThemeProvider в App.js. Для этого сейчас, чтобы получить визуальный отзыв, мы собираемся применить одну из тем из themes объект в globalStyle.js это так, когда мы добавляем компоненты, мы видим, как применяется тема.

Мы можем сделать это сейчас с помощью AppHeader который является стилизованным div:

const AppHeader = styled.div`
  height: 12rem;
  padding: 1rem;
  color: ${({ theme }) => theme.dark};
  background-color: ${({ theme }) => theme.primary};
`;

Здесь вы заметите, что мы начинаем использовать styled-components, theme props, но, если мы вставим этот код сейчас, никаких изменений не будет до ThemeProvider передается theme объект, поэтому мы собираемся завернуть App.js с ThemeProvider компонент так, чтобы любой компонент, инкапсулированный ThemeProvider умеет получать theme реквизит.

nuyaw29uoex6qcluf8va

AppTitle будет h1, поэтому:

const AppTitle = styled.h1`
  font-family: ${({ theme }) => theme.fontHeader};
`;

Для вращающегося логотипа React мы можем использовать ресурс, который использовался ранее в примере начала работы со стилизованными компонентами

Мы можем добавить его с помощью импорта вверху App.js компонент и добавьте его в AppLogo стилизованный компонент как an img тег:

const logo = `
    234708/37256552-32635a02-2554-11e8-8fe3-8ab5bd969d8e.png`;

The keyframes helper нужно будет импортировать вместе с ThemeProvider для анимации на логотипе react.

const rotate360 = keyframes`
  from { 
    transform: rotate(0deg); 
  }
  to { 
    transform: rotate(360deg); 
  }
`;

const AppLogo = styled.img`
  animation: ${rotate360} infinite 5s linear;
  height: 80px;
  &:hover {
    animation: ${rotate360} infinite 1s linear;
  }
`;
pxe3fb5zqvprvtjthq5b

Общие компоненты

Общие компоненты описаны в руководстве с начала работы со стилизованными компонентами, если вам нужна дополнительная информация, для этого примера мы собираемся представить последнюю пару компонентов как общие для StyledHyperLink и Button в src/Shared.js добавить следующее:

src/Shared.js

import styled, { css } from 'styled-components';

export const Button = styled.button`
  padding: 0.5rem 1rem;
  margin: 0.5rem 1rem;
  color: ${({ theme }) => theme.primary};
  font-size: 1rem;
  box-shadow: 0 3px 5px rgba(0, 0, 0, 0.1);
  cursor: pointer;
  border: 2px solid ${props => props.border};
  background-color: Transparent;
  text-transform: uppercase;
  border-radius: 4px;
  transition: all 0.1s;
  &:hover {
    transform: translateY(1px);
    box-shadow: 0 2px 3px rgba(0, 0, 0, 0.15);
  }
  ${props =>
    props.primary &&
    css`
      background: ${({ theme }) => theme.primary};
      border: 2px solid ${({ theme }) => theme.primary};
      color: white;
    `};
  ${props =>
    props.danger &&
    css`
      background: ${({ theme }) => theme.danger};
      border: 2px solid ${({ theme }) => theme.danger};
      color: white;
    `};
  &:hover {
    transform: translateY(2px);
    box-shadow: 0 2px 3px rgba(0, 0, 0, 0.15);
  }
`;

export const StyledHyperLink = styled.a`
  cursor: pointer;
  &:visited,
  &:active {
    color: ${({ theme }) => theme.primary};
  }
  &:hover {
    color: ${({ theme }) => theme.secondary};
  }
  color: ${({ theme }) => theme.primary};
`;

Затем импортируйте компоненты, как и любые другие:

ipi1kdmy83ieiw6sppog

Последние три компонента на данный момент, AppIntro, Underline и StyledHyperLink:

const AppIntro = styled.p`
  color: ${({ theme }) => theme.dark};
  font-size: large;
  code {
    font-size: 1.3rem;
  }
  font-family: ${({ theme }) => theme.fontBody};
`;

const Underline = styled.span`
  border-bottom: 4px solid ${({ theme }) => theme.secondary};
`;

const StyledHyperLink = SHL.extend`
  text-decoration: none;
  font-family: ${({ theme }) => theme.fontBody};
  color: ${({ theme }) => theme.fontDark};
`;
smm6hpg2w71sxm6nf3ln

Добавьте их под AppLogo стилизованный компонент, а затем мы можем добавить остальные компоненты к App функция return, Итак, готовы к очередной копии макарон? здесь:

<AppIntro>
  Bootstrapped with{' '}
  <Underline>
    <code>
      <StyledHyperLink
        href={`
        target="_blank"
        rel="noopener"
      >
        create-react-app
      </StyledHyperLink>
    </code>
  </Underline>.
</AppIntro>
<AppIntro>
  Components styled with{' '}
  <Underline>
    <code>
      <StyledHyperLink
        href={`
        target="_blank"
        rel="noopener"
      >
        styled-components
      </StyledHyperLink>
    </code>
  </Underline>{' '}
  <span role="img" aria-label="nail polish">
    ?
  </span>
</AppIntro>
<AppIntro>
  Fonts picked with{' '}
  <Underline>
    <code>
      <StyledHyperLink
        href={`
        target="_blank"
        rel="noopener"
      >
        fontjoy.com
      </StyledHyperLink>
    </code>
  </Underline>
</AppIntro>
<Button>Normal Button</Button>
<Button primary>Primary Button</Button>
<Button danger>Danger Button</Button>

Простите за кодовую стену! Право вставьте это под крышку </AppHeader> тег, и мы должны иметь основу для темы, что мы собираемся!

zfcnihvmyvb9my5dn11x

В порядке? Как это смотрится?

Теперь у нас есть базовая программа React, использующая стилированные компоненты!

Используйте React Context API

Теперь главное событие! Здесь мы рассмотрим:

Ввод темы в контекст.

Использование контекстного API с компонентом.

Использование Context API в нескольких компонентах.

Таким образом, мы можем использовать Context API, чтобы избежать излишней передачи состояния через компоненты. Если мы посмотрим пример для начала работы со стилизованными компонентами, мы увидим, что состоянием управляют в файле App.js компонент и handleThemeChange функция должна быть передана в ThemeSelect компонент так же, как и какие-либо реквизиты, которые нужно будет передать. Это упрощенный пример, но достаточно легко представить, если бы этот компонент существовал в компоненте нижнего колонтитула или в пункте меню, было бы несколько других компонентов, которым нужно было передать состояние через них, которые на самом деле не нуждались бы в этом состоянии или параметрах. Иметь смысл?

пример

<App>               {/* state begins here */}
  <Header>          {/* through here */}
    <Navigation>    {/* and here */}
      <ThemeSelect> {/* to be used here */}
    </Navigation>
  </Header>
  <Footer/>
</App>

Разместите контекст темы сайта

В нашем src/contexts/ каталог, который мы собираемся создать SiteThemeContext.jsимпортируйте React и определите и экспортируйте наш контекст:

import React from 'react';

export const SiteThemeContext = React.createContext();

Итак, что же такое контекст?

Контекст состоит из двух вещей, поставщика и потребителя, у вас есть единственный поставщик, который будет размещаться как можно выше в дереве компонентов, чтобы несколько потребителей могли получить состояние и реквизиты от поставщика.

Надеемся, вы помните момент, на котором мы абстрагировали function App компонент из src/index.js файл, это для того, чтобы мы могли добавить поставщик контекста на самом высоком уровне программы, в файле src/index.js файл. Это означает, что любой потребитель в приложении независимо от того, насколько глубоко он находится в дереве компонентов, он может получить состояние и параметры из этого верхнего уровня.

Теперь для создания поставщика поставщик является обычным компонентом React, поэтому:

import React from 'react'

export const SiteThemeContext = React.createContext()

export class SiteThemeProvider extends React.Component {
  render() {
    return (
      <SiteThemeContext.Provider value={}>
        {this.props.children}
      </SiteThemeContext.Provider>
    )
  }
}

Возвращающийся <SiteThemeProvider> есть <SiteThemeContext.Provider> и дочерних компонентов этого компонента, единственным реквизитом, который вы должны предоставить поставщику, является a value опора. Это переменная, в которую имеет доступ потребитель. Потребительское существо <SiteThemeContext.Consumer> (подробнее об этом вскоре).

Так что то, что мы можем сделать сейчас, это иметь то, во что передано value быть объектом value={{}} поэтому он может сохранять несколько свойств состояния и функций, определенных в SiteThemeContext.

Состояние для контекста должно быть theme поэтому нам нужно импортировать тему из src/theme/globalStyle и добавим это в состояние, мы собираемся установить тему (и состояние) по умолчанию theme1 и добавьте его копию к value поддержка путем распространения в состояние ...❤️это должно выглядеть так:

import React from 'react';
import PropTypes from 'prop-types';

import { themes } from '../theme/globalStyle';

export const SiteThemeContext = React.createContext();

export class SiteThemeProvider extends React.Component {
  state = {
    theme: themes['theme1'],
  };

  render() {
    return (
      <SiteThemeContext.Provider
        value={{
          ...this.state,
        }}>
        {this.props.children}
      </SiteThemeContext.Provider>
    );
  }
}

Ладно, прошло время с тех пор, как я добавил gif, время для еще одного!

n2qbxs7cbf7w5opqcri2

И внесите themes и добавить состояние:

y6n32p1gshah5ex747mu

Теперь мы можем добавить функцию к поставщику, чтобы изменить состояние темы на основе того, что было выбрано с помощью handleThemeChange значение события:

handleThemeChange = e => {
  const key = e.target.value;
  const theme = themes[key];
  this.setState({ theme });
};

Это может быть использовано любым поставщиком, который захочет его использовать, нам нужно будет добавить его в value опора, вот так:

import React from 'react';
import PropTypes from 'prop-types';

import { themes } from '../theme/globalStyle';

export const SiteThemeContext = React.createContext();

export class SiteThemeProvider extends React.Component {
  state = {
    theme: themes['theme1'],
  };

  handleThemeChange = e => {
    const key = e.target.value;
    const theme = themes[key];
    this.setState({ theme });
  };

  render() {
    return (
      <SiteThemeContext.Provider
        value={{
          ...this.state,
          handleThemeChange: this.handleThemeChange,
        }}>
        {this.props.children}
      </SiteThemeContext.Provider>
    );
  }
}

Ладно, это рассмотрен компонент контекста темы сайта, достаточно просто, не так ли?

Что я должен отметить, так это то, что e в handleThemeChange функция будет событием из поля выбора темы, которую мы собираемся сделать.

Давайте добавим функцию и добавим ее в состояние:

3bh3bwi4ekb24uowvm65

И теперь мы можем добавить поставщика темы src/index.js поэтому все, что находится ниже в дереве зависимостей, может получить к нему доступ через потребителя.

p8nibx8ecfildi92jscm

Разместите выбранную тему

Теперь мы хотим позвонить handleThemeChange функция, входящая в состав SiteThemeProvider через SiteThemeContext! Я уверен, что сейчас все это имеет смысл (?), поэтому давайте перейдем к нему и определим компонент, который мы будем использовать для использования. SiteThemeContext.Provider с ThemeSelect компонент!

В src/components каталог добавить новый ThemeSelect.js компонент, именно здесь мы будем использовать контекст темы сайта с потребителем.

Дочерний элемент потребителя – это не компонент, а функция, поэтому нам нужно будет выбрать тему внутри возвращения этой функции.

Давайте сначала настроим стилизованные компоненты, которые будут составлять выбор, являющийся полем выбора, некоторыми параметрами и оберткой.

Сначала мы сделаем это без потребителя, затем добавим его.

ThemeSelect.js

import React from 'react';
import styled from 'styled-components';

import { themes } from '../theme/globalStyle';

const SelectWrapper = styled.div`
  margin: 0rem 0.5rem 0rem 0.25rem;
  padding: 0rem 0.5rem 0rem 0.25rem;
`;

const Select = styled.select`
  margin: 1.5rem 0.5rem;
  padding: 0.25rem 0.5rem;
  font-family: ${({ theme }) => theme.fontBody};
  border: 2px solid ${({ theme }) => theme.secondary};
  box-shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.1);
  background: ${({ theme }) => theme.foreground};
  border-radius: 4px;
`;

export const SelectOpt = styled.option`
  font-family: ${({ theme }) => theme.fontBody};
`;

const ThemeSelect = props => {
  return (
    <SelectWrapper>
      <Select>
        {Object.keys(themes).map((theme, index) => {
          return (
            <SelectOpt key={index} value={theme}>
              Theme {index + 1}
            </SelectOpt>
          );
        })}
      </Select>
    </SelectWrapper>
  );
};

export default ThemeSelect;
43e15llsi8uhlmi1z1ut

Следовательно, из этого мы можем перечислить эти темы, доступные нам в themes объект. Но это все, функция обработки смены темы живет на SiteThemeProvider.

Вернуться к SiteThemeContext.Consumer как я уже упоминал ранее, ребенок потребителя является функцией () => () первый раздел – это value от провайдера (<SiteThemeContext.Provider>), поэтому давайте быстро посмотрим на то, что мы раньше определили в провайдере:

value={{
  ...this.state,
  handleThemeChange: this.handleThemeChange
}}

доступен из SiteThemeContext.Provider является состоянием и функцией, поэтому любой из этих элементов мы можем извлечь и передать поставщику или, другими словами, потребитель может получить доступ к этим значениям.

Здесь мы можем использовать деструктуризацию, чтобы вытащить handleThemeChange функция необходимо изменить тему.

import React from 'react'

import { SiteThemeContext } from '../contexts/SiteThemeContext'

const ThemeSelect = props => {
  return (
    <SiteThemeContext.Consumer>
      {({ handleThemeChange }) => ()}
    </SiteThemeContext.Consumer>
  )
}

export default ThemeSelect
1qq4hc2zqa50t0t2vi5v

Пока это не изменит тему, потому что мы имеем это жестко закодировано в стилизованных компонентах ThemeProviderмы хотим использовать потребителя для текущей выбранной темы в SiteThemeContext.

Перед этим нам также нужно будет добавить onChange событие, которое мы хотим использовать для передачи события (e) до handleThemeChange функция включена SiteThemeContext.

Затем в App компонент, который мы можем импортировать <SiteThemeContext.Consumer> потреблять theme на SiteThemeContext состояние и передать его в styled-components ThemeProvider.

jn5u8bzuvufpa56c9ta7

Хотите узнать больше?

Как упоминалось в начале этой статьи, отличным ресурсом является @leighchalliday и его канал на YouTube, где вы можете найти его отличный вариант использования React Context API.

Также есть сообщество React о спектре и styled-components о спектре.

Пример кода пошагового руководства доступен на CodeSandbox.

Спасибо, что прочли

Если я что-то пропустил, или есть лучший способ сделать что-нибудь, пожалуйста, сообщите мне.

Следите за мной в Twitter или спросите что-нибудь на GitHub.

Вы можете прочесть другие подобные статьи в моем блоге.

Добавить комментарий

Ваш адрес email не будет опубликован.