Как использовать createContext с хуком

Итак, в React правила хуков говорят, что хуки нельзя вызывать вне функциональных компонентов.

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

Что я пробовал

const utils = useUtils(); //useUtils is a hook from a date library

export const ScheduleContext = createContext({
  scheduleStartDate: utils.date().add(2, "days"), //using the hook here
  ...  
});

Мой провайдер пытается передать состояние вот так...

  const { scheduleStartDate } = useContext(ScheduleContext);
    <ScheduleContext.Provider
      value = {{
        scheduleStartDate: scheduleStartDate,
      }}
    >
      {children}
    </ScheduleContext.Provider>

Я получаю сообщение об ошибке: Неверный вызов перехватчика. Хуки можно вызывать только внутри тела функционального компонента.

Ожидаете ли вы, что значение по умолчанию когда-либо будет использоваться? В большинстве случаев использования контекста значение по умолчанию не имеет значения, поскольку значение поступает от поставщика, а не по умолчанию. (Под «значением по умолчанию» я имею в виду объект, который вы передаете createContext)

Nicholas Tower 18.06.2024 05:39
scheduleStartDate или scheduleEndDate? Это смущает
Phil 18.06.2024 05:44
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
2
2
73
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вероятно, вам не нужно значение по умолчанию для вашего контекста. Значение по умолчанию используется только в том случае, если выше в дереве компонентов нет ScheduledContext.Provider, и вы можете расположить свои компоненты так, чтобы этого никогда не происходило.

Если вам не нужно значение по умолчанию, вы можете подождать, пока провайдер не будет вызывать useUtils. Например:

export const ScheduleContext = createContext(null);
// ...
const MyProvider = ({ children }) => {
  const utils = useUtils();
  return (
    <ScheduleContext.Provider value = {{ 
      scheduledStartDate: utils.date().add(2, "days")
    }}>
      {children}
    </ScheduledContext.Provider>
  )
}

Как при такой настройке компонент, завернутый в поставщика, будет читать реквизиты? Разве им не нужно импортировать ScheduleContext и деконструировать из него реквизиты, чтобы их прочитать? Я зациклен на том, как дочерние компоненты смогут читать ScheduleStartDate.

Yusef Daramay 18.06.2024 13:57

Дочерний компонент импортирует ScheduleContext, а затем вызывает const { scheduledStartDate } = useContext(ScheduleContext) во время рендеринга.

Nicholas Tower 18.06.2024 14:20

Спасибо! Я слишком усложнил это и не знал, что createContext может иметь такое же значение null. Починил это.

Yusef Daramay 18.06.2024 20:40

Да, когда вы вызываете useContext(ScheduleContext), React будет искать в дереве компонентов ближайший <ScheduleContext.Provider> и возвращать его значение. Единственный способ вернуть null (или другое значение по умолчанию) — это если <ScheduleContext.Provider> не существует. Поэтому, пока вы отображаете <ScheduleContext.Provider> в верхней части дерева компонентов, вам никогда не придется иметь дело со значением по умолчанию.

Nicholas Tower 18.06.2024 21:02

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

Из createContext()

Параметры

  • defaultValue: значение, которое вы хотите, чтобы контекст имел, когда в дереве над компонентом, считывающим контекст, нет соответствующего поставщика контекста. Если у вас нет значимого значения по умолчанию, укажите null. Значение по умолчанию предназначено как запасной вариант «последней меры». Оно статично и никогда не меняется со временем.

Вместо этого установите реальную стоимость с помощью собственного компонента поставщика.

const ScheduleContext = createContext({
  scheduleStartDate: new Date(), // or literally anything really
  // ...
});

// define a context provider component
const ScheduleContextProvider = ({ children }) => {
  const { date } = useUtils();
  const scheduleStartDate = date().add(2, 'days');

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

// this is also a very handy custom hook for your context
const useSchedule = () => useContext(ScheduleContext);

export { ScheduleContextProvider as default, useSchedule };

Я предпочитаю устанавливать реальное значение по двум причинам...

  1. Это предотвращает возможные ошибки во время выполнения, такие как «Невозможно прочитать свойства со значением null» или «Невозможно деструктурировать свойство «x» со значением «null».
  2. Если вы используете TypeScript, это позволяет вам избежать проверки потенциальных нулей каждый раз, когда вы хотите использовать свой контекст.

Другие вопросы по теме

Перенаправление на главную страницу после входа или регистрации не работает. Firebase, частный маршрут, аутентификация по электронной почте
Всплывающее меню с использованием контекста реагирования повторно открывается при закрытии его кнопкой
Материал Tailwind — TypeError: невозможно прочитать свойства null (чтение «useContext»)
Почему контекст нельзя использовать в клиенте?
Проблема с использованием поставщика контекста в методе onMessage() реакции-native-firebase/messaging?
Сетка данных React MUI: как получить индекс текущей строки для React-Context
Почему возникает ошибка «Нет перегрузки, соответствующей этому вызову»?
Как разделить контекст между двумя функциональными компонентами, которые будут отображаться в разных createNodes? нужно вызвать этот код в моем существующем приложении js
Есть ли способ решить эту проблему? Введите '{ Children: Element; }» не имеет общих свойств с типом «IntrinsicAttributes».?
Как создать функцию фильтра с вызовом API и контекстом?