Как изменить значение контекста с помощью useContext?

Использование хука useContext с React 16.8+ работает хорошо. Вы можете создать компонент, использовать хук и значения контекста без каких-либо проблем.

В чем я не уверен, так это в том, как применить изменения к значениям поставщика контекста.

1) Является ли хук useContext строго средством потребления значений контекста?

2) Есть ли рекомендуемый способ с помощью хуков React для обновления значений из дочернего компонента, который затем вызовет повторную визуализацию компонента для любых компонентов, использующих хук useContext в этом контексте?

const ThemeContext = React.createContext({
  style: 'light',
  visible: true
});

function Content() {
  const { style, visible } = React.useContext(ThemeContext);

  const handleClick = () => {
    // change the context values to
    // style: 'dark'
    // visible: false
  }

  return (
    <div>
      <p>
        The theme is <em>{style}</em> and state of visibility is 
        <em> {visible.toString()}</em>
      </p>
      <button onClick = {handleClick}>Change Theme</button>
    </div>
  )
};

function App() {
  return <Content />
};

const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
<div id = "root"></div>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/16.8.2/umd/react.production.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.2/umd/react-dom.production.min.js"></script>
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
109
0
77 237
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

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

Аргумент, переданный createContext, будет значением по умолчанию, только если компонент, который использует useContext, не имеет Provider над ним выше по дереву. Вместо этого вы можете создать Provider, который предоставляет style и visibility, а также функции для их переключения.

Пример

const { createContext, useContext, useState } = React;

const ThemeContext = createContext(null);

function Content() {
  const { style, visible, toggleStyle, toggleVisible } = useContext(
    ThemeContext
  );

  return (
    <div>
      <p>
        The theme is <em>{style}</em> and state of visibility is
        <em> {visible.toString()}</em>
      </p>
      <button onClick = {toggleStyle}>Change Theme</button>
      <button onClick = {toggleVisible}>Change Visibility</button>
    </div>
  );
}

function App() {
  const [style, setStyle] = useState("light");
  const [visible, setVisible] = useState(true);

  function toggleStyle() {
    setStyle(style => (style === "light" ? "dark" : "light"));
  }
  function toggleVisible() {
    setVisible(visible => !visible);
  }

  return (
    <ThemeContext.Provider
      value = {{ style, visible, toggleStyle, toggleVisible }}
    >
      <Content />
    </ThemeContext.Provider>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src = "https://unpkg.com/react@16/umd/react.development.js"></script>
<script src = "https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id = "root"></div>

Так правильно ли говорить, что единственное значение хука useContext заключается в том, что он позволяет вам избежать обертывания компонента родителем Context.Consumer и передачи значения контекста через вызов функции визуализируемому дочернему элементу?

Randy Burgess 18.02.2019 02:48

@RandyBurgess Да, верно. Создание контекста с помощью хуков работает так же, как и раньше, просто вы используете его с помощью хука useContext, а не Context.Consumer с помощью рендеринга, о котором вы упомянули.

Tholle 18.02.2019 09:54

Не приведет ли установка value к объекту, подобному этому, к повторному рендерингу всех потребителей каждый раз, когда провайдер повторно рендерит, на раздел оговорок контекстной документации?

neurodynamic 27.04.2020 05:41

Так как же предотвратить постоянный повторный рендеринг при использовании хука useState для переменной, которая передается провайдеру?

Bombe 06.06.2020 12:02

Здравствуйте, поэтому мы должны передать функции состояний провайдеру в качестве реквизита в App.js. Есть ли способ поместить эти функции в другой файл (сервис или магазин) и импортировать его? Это кажется сложным, потому что функции useState и функции, которые их вызывают (например, toggleVisible), должны быть в компоненте, который отображает поставщика контекста. Мы не можем импортировать его из другого компонента.

Getzel 16.08.2020 20:54

Ожидаемый тип исходит из свойства «значение», которое объявлено здесь для типа «IntrinsicAttributes & ProviderProps <null>» — поскольку мы установили createContext с нулевым значением, я не могу передать данные в реквизиты значения.

doobean 11.09.2020 20:44

Вы можете использовать этот подход, независимо от того, сколько у вас вложенных компонентов, он будет работать нормально.

// Settings Context - src/context/Settings
import React, { useState } from "react";

const SettingsContext = React.createContext();

const defaultSettings = {
  theme: "light",
};

export const SettingsProvider = ({ children, settings }) => {
  const [currentSettings, setCurrentSettings] = useState(
    settings || defaultSettings
  );

  const saveSettings = (values) => {
   setCurrentSettings(values)
  };

  return (
    <SettingsContext.Provider
      value = {{ settings: currentSettings, saveSettings }}
    >
      {children}
    </SettingsContext.Provider>
  );
};

export const SettingsConsumer = SettingsContext.Consumer;

export default SettingsContext;
// Settings Hook - src/hooks/useSettings
import { useContext } from "react";
import SettingsContext from "src/context/SettingsContext";

export default () => {
  const context = useContext(SettingsContext);

  return context;
};
// src/index
ReactDOM.render(
  <SettingsProvider settings = {settings}>
    <App />
  </SettingsProvider>,
  document.getElementById("root")
);
// Any component do you want to toggle the theme from
// Example: src/components/Navbar
const { settings, saveSettings } = useSettings();

const handleToggleTheme = () => {
  saveSettings({ theme: "light" });
};

«Неверный вызов ловушки. Хуки можно вызывать только внутри тела функционального компонента».

Kevin Danikowski 27.07.2020 17:43

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

Anurag Dabas 15.04.2021 20:28

Boy FB знает, как все усложнять, TLDR, вместо этого используйте svelte

SuperUberDuper 01.06.2021 14:50

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