* Не стесняйтесь переходить к следующей части, если вы уже знаете, что такое Контекст.

Так что же такое контекст? Контекст - это хорошо, контекст вашего приложения. Или просто это глобальное состояние вашего приложения. Учтите, что когда вы используете useState (или this.state, если вы не используете хуки), вы более или менее устанавливаете локальное состояние, которое определяет этот компонент, в котором он установлен. Но что, если нам нужно это состояние в компоненте, который глубоко вложенный (или даже всего на несколько шагов вниз)?

До Context (или Redux) подход заключался в поддержке тренировки. то есть передавать состояние от ребенка к ребенку, пока оно не достигнет того места, где оно было необходимо, и это все усложнило. И теперь у нас есть Redux ... и теперь есть Context (который, я думаю, лучше, чем Redux в том смысле, что вам не нужна дополнительная библиотека для работы с глобальным состоянием). Теперь вам больше не нужно подпирать дрель, вы можете просто передать ее непосредственно тем компонентам, которые в ней нуждаются!

Итак, как нам использовать React Context?

  1. Создайте пустое приложение React

Для начала давайте создадим пустой проект React, запущенный с помощью npx create-response-app (или любого другого метода, который вы предпочитаете). Вы можете использовать свой существующий проект, но, чтобы случайно не навести беспорядок, я бы рекомендовал начать все сначала, а затем реализовать то, что вы узнали, в своем собственном проекте. Обычно я настраиваю файловую структуру проекта React следующим образом:

2. Создать файл контекста

После того, как вы создали приложение React, создайте каталог с именем state, который является папкой, которую я выбрал на этом снимке экрана. Затем создайте внутри файл с именем Context.jsx. На самом деле это можно называть как угодно, но убедитесь, что название написано так, что вы знаете, что это ваш контекст. Я настоятельно рекомендую поместить "контекст" где-нибудь в названии.

Если вам интересно, почему я использую расширения файлов JSX, то это потому, что правильно использовать jsx, когда ваш файл содержит элементы JSX. Это упрощает отличия от файла с обычным, ванильным JS и с компонентом React. Если вы используете Typescript, это будет TSX или TS (для ванильного кода Typescript).

3. Создание контекста

Чтобы создать контекст, сначала мы должны импортировать createContext из response, а затем назначить переменной функцию createContext, передав ей пустой объект. createContext () ожидает по крайней мере один аргумент, определяющий переменную по умолчанию. Если у вас есть глобальные состояния, которые вы не хотите, чтобы они менялись, вы можете поместить их здесь и исключить из следующей части (я не думаю, что они будут отменены, но если они будут сообщены мне).

import { createContext } from 'react';

const Context = createContext({})

Наконец, экспортируйте его по умолчанию.

export default Context;

Наш законченный контекст должен выглядеть примерно так:

4. Создайте поставщика

Где контекст, там и состояние. Погодите, разве контекст не наше состояние? Нет, не совсем так. Технически вы можете получить контекст, и он вернет значение по умолчанию, но есть одна проблема ... вы не можете его изменить. Это действительно делает контекст бесполезным, если он не является действительно постоянным и не меняется в течение жизненного цикла вашего приложения.

Теперь создайте файл Provider.jsx и импортируйте Context и useState из react.

import React, { useState } from 'react';
import Context from './Context';

Создайте компонент Provider:

const Provider = ({ children }) => {}

Теперь давайте сделаем глобальные состояния.

const [coords, setCoords] = useState({lat: 0, lng: 0});

const value = {
    coords,
    setCoords
}

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

А теперь давайте накормим наших детей… хм, контекст.

return (
    <Context.Provider value={value}>
        {children}
    </Context.Provider>
);

Чтобы понять, что здесь происходит, у каждого контекста есть объект провайдера, который содержит все предоставленные ему контексты. Здесь мы передаем структурированный объект, который мы создали, в состояниях, которые мы установили. Это изменит значения контекста, которые затем будут переданы его дочерней опоре.

Свойство children - это то, что предоставляется react, и оно содержит всех дочерних компонентов React Component. В этом случае все дочерние элементы Provider.

Это конечный результат:

5. Предоставьте нашему приложению наш контекст

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

Откройте компонент индекса и импортируйте компонент поставщика.

import Provider from './state/Provider';

Теперь, когда React.Strict по умолчанию вызывает предупреждение на нашей консоли, я удаляю фрагмент ‹React.Strict›, чтобы избежать необходимости исправлять это предупреждение.

ReactDOM.render(
    <Provider>
        <Router>
            <App />
        </Router>
    </Provider>,
  document.getElementById('root')
);

Подождите, что? У меня нет роутера! Я объясню, почему у нас это есть ... импортируйте Router из response-router-dom (вам также нужно будет установить пакет) и включите компонент Router, как это сделал я.

Что касается предоставления нашему приложению только что созданного контекста? хорошо…

Итак, теперь, когда у вас есть контекст во всем приложении, это немного бессмысленно, если вы не можете его изменить, верно? По крайней мере, я так думаю. Я хочу иметь возможность переключаться между светлым и темным режимами на всех страницах один раз и держать это так, черт возьми.

Итак, на данный момент вы, вероятно, уже знаете, как создавать страницы и перемещаться между ними. По крайней мере, я надеюсь, что вы это сделаете, потому что это руководство не для этого, и я не собираюсь излагать эти шаги, извините ... (Если вы очень любезны, возможно, я напишу учебник по React Routes, Switches и Ссылки).

Итак, давайте сделаем это. Создайте простую страницу формы с двумя входами и, конечно же, кнопкой отправки (у вас также может быть локальное состояние для хранения значений ваших двух входов и useEffect для изменения контекста, если вам нужно что-то подобное). Вот как теперь выглядит моя файловая структура:

Итак, сначала давайте узнаем, как получить контексты, которые мы предоставили нашим детям. Откройте свою домашнюю страницу и импортируйте useContext из React. Давайте также включим useEffect, например:

import React, { useContext, useEffect } from 'react';

Теперь мы создаем константу, которая будет содержать контекст coords (или впоследствии любые нужные вам контексты).

const { coords } = useContext(Context);

Теперь давайте добавим наши useEffect и console.log наши координаты при загрузке страницы.

useEffect(() => { console.log(coords) });

Попробуйте, и вы заметите, что он регистрирует {lat: 0, lng: 0}. Идеально. Это настройка моей домашней страницы:

Итак, теперь нужно это изменить. Это можно сделать разными способами, но для координат давайте создадим простую форму с двумя входами и кнопкой отправки. Так выглядит моя форма. Ничего стильного, просто простая, труднодоступная форма:

Файл Change.jsx, который вы видели ранее, просто отображает этот компонент.

Итак, вы заметите, что при нажатии на кнопку «Отправить» вы получите console.log с вашими новыми координатами. Но если вы вернетесь на свою главную страницу, вы заметите, что они возвращаются в состояние по умолчанию. Такова природа React. Как только вы вернетесь в свой дом, страница формы будет удалена, а ваша домашняя страница будет удалена, когда вы уйдете.

Но на самом деле это меняется! Для доказательства импортируйте контекст в компонент приложения и запишите туда координаты в консоли. Перейдите к созданной вами форме и измените координаты. Теперь вы увидите два журнала. Один из вашего приложения (который всегда отображается) и один из вашей страницы формы. Итак, если это не сохраняется, в чем истинный смысл контекста?

Что ж, в отличие от этого простого приложения React, ваше приложение React, вероятно, будет более сложным с гораздо большим количеством компонентов, встроенных друг в друга и отображаемых на экране. Истинная идея Context заключается в том, что вы можете установить его для своего родительского компонента (страницы) и передать его этим глубоко вложенным дочерним компонентам без необходимости поддерживать детализацию.

Если вы хотите, чтобы Context сохранялся при повторной визуализации, вы должны использовать localStorage или sessionStorage. (вы бы установили значение контекста по умолчанию на что-то вроде sessionStorage.getItem ('item'). Вы захотите установить его на уровне выше, чем тот, на котором вы предоставляете Context, и убедитесь, что он не загружается до тех пор, пока задано хранилище. В зависимости от вашего варианта использования вы можете просто создать глобальную переменную со значением этого sessionStorage в области компонента, в котором вы хотите ее использовать.

Вы также можете изучить Redux. Я еще не использовал его, но одна из его особенностей - постоянство состояния.

И это, друзья мои, вот как вы делаете React Context. Я надеюсь, вы найдете это полезным.