Как обновить значение контекста в поставщике от потребителя
MyContext.js
import React from "react";
const MyContext = React.createContext('test');
export default MyContext;
Создал отдельный js файл контекста, в котором я могу получить доступ как в родительском, так и в моем дочернем компоненте
Parent.js
import MyContext from "./MyContext.js";
import Child from "./Child.js";
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
Message: "Welcome React",
ReturnMessage:""
};
}
render() {
return (
<MyContext.Provider value={{state: this.state}}>
<Child />
</MyContext.Provider>
)
}
}
Таким образом, создан родительский компонент с контекстом поставщика и вызовом дочернего компонента на вкладке поставщика
Child.js
import MyContext from "./MyContext.js";
class Child extends Component {
constructor(props) {
super(props);
this.state = {
ReturnMessage:""
};
}
ClearData(context){
this.setState({
ReturnMessage:e.target.value
});
context.state.ReturnMessage = ReturnMessage
}
render() {
return (
<MyContext.Consumer>
{(context) => <p>{context.state.Message}</p>}
<input onChange={this.ClearData(context)} />
</MyContext.Consumer>
)
}
}
Таким образом, у ребенка с помощью потребителя может отображаться часть дочернего рендеринга.
Я столкнулся с обновлением от потребителя до состояния поставщика.
Как обновить состояние поставщика или управлять состоянием поставщика.
Ответы
Ответ 1
Во-первых, чтобы обновить контекст от потребителя, вам нужно получить доступ к контексту вне функции рендеринга. Подробнее о том, как это сделать, проверьте
Контекст доступа к контексту вне функции рендеринга
Во-вторых, вы должны предоставить обработчик от поставщика, который обновляет значение контекста и не изменяет его напрямую. Ваш код будет выглядеть так:
Parent.js
import MyContext from "./MyContext.js";
import Child from "./Child.js";
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
Message: "Welcome React",
ReturnMessage:""
};
}
updateValue = (key, val) => {
this.setState({[key]: val});
}
render() {
return (
<MyContext.Provider value={{state: this.state, updateValue: this.updateValue}}>
<Child />
</MyContext.Provider>
)
}
}
ребенок
import MyContext from "./MyContext.js";
class Child extends Component {
constructor(props) {
super(props);
this.state = {
ReturnMessage:""
};
}
ClearData(e){
const val = e.target.value;
this.setState({
ReturnMessage:val
});
this.props.context.updateValue('ReturnMessage', val);
}
render() {
return (
<React.Fragment>
<p>{this.props.context.state.Message}</p>}
<input onChange={this.ClearData} />
</React.Fragment>
)
}
}
const withContext = (Component) => {
return (props) => {
<MyContext.Consumer>
{(context) => {
return <Component {...props} context={context} />
}}
</MyContext.Consumer>
}
}
export default withContext(Child);
Ответ 2
Вам нужно написать функцию в компоненте Provider для обновления State. Чтобы быть точным, потребитель может использовать только те значения и функции, которые вы написали в компоненте Provider.
В родительском компоненте
updateReturnMessage = (ReturnMessage) => {
this.setState((prevState) => ({ ...prevState, ReturnMessage }))
}
<MyContext.Provider value={{ state: this.state, updateReturnMessage: this.updateReturnMessage }}>
// your code goes here
</MyContext.Provider>
В дочернем компоненте:
ClearData(e){
const val = e.target.value;
this.context.updateReturnMessage(val);
}
Эта функция похожа на action creators
доступных в Redux
и flux
Ответ 3
Обновление контекста из вложенного компонента
Часто необходимо обновить контекст компонента, который находится где-то глубоко в дереве компонентов. В этом случае вы можете пропустить функцию через контекст, чтобы потребители могли обновить контекст:
тема-context.js
// Make sure the shape of the default value passed to
// createContext matches the shape that the consumers expect!
export const ThemeContext = React.createContext({
theme: themes.dark,
toggleTheme: () => {},
});
тема-Toggler-button.js
import {ThemeContext} from './theme-context';
function ThemeTogglerButton() {
// The Theme Toggler Button receives not only the theme
// but also a toggleTheme function from the context
return (
<ThemeContext.Consumer>
{({theme, toggleTheme}) => (
<button
onClick={toggleTheme}
style={{backgroundColor: theme.background}}>
Toggle Theme
</button>
)}
</ThemeContext.Consumer>
);
}
export default ThemeTogglerButton;
app.js
import {ThemeContext, themes} from './theme-context';
import ThemeTogglerButton from './theme-toggler-button';
class App extends React.Component {
constructor(props) {
super(props);
this.toggleTheme = () => {
this.setState(state => ({
theme:
state.theme === themes.dark
? themes.light
: themes.dark,
}));
};
// State also contains the updater function so it will
// be passed down into the context provider
this.state = {
theme: themes.light,
toggleTheme: this.toggleTheme,
};
}
render() {
// The entire state is passed to the provider
return (
<ThemeContext.Provider value={this.state}>
<Content />
</ThemeContext.Provider>
);
}
}
function Content() {
return (
<div>
<ThemeTogglerButton />
</div>
);
}
ReactDOM.render(<App />, document.root);
Приведенный выше пример взят из документов React Context API v.8.8.6 и является рекомендуемым способом обновления значения контекста от потребителя. https://reactjs.org/docs/context.html#updating-context-from-a-nested-component
Ответ 4
@nowshad, вы пытаетесь использовать с redux? Тогда я предлагаю использовать провайдера
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import todoApp from './reducers'
import App from './components/App'
const store = createStore(todoApp)
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
Если вы используете только несколько компонентов, и вы хотите иметь значения для всех вложенных компонентов в соответствии с вашим выражением
For nested components can i have one provider and multiple consumers For an Example : 1 is an parent , 1.1 is a child to 1 and 1.1.1 is child to 1.1, Can i have provider to 1 and consumers to 1.1 and 1.1.1
то я предлагаю вам просто передать обработчик вниз в качестве опоры и как только вы захотите изменить вызов состояния обработчиком, и он изменит значения во всех ваших компонентах (это должно быть сделано, если у вас есть только несколько дочерних компонентов, которым все требуют одинаковых значения)
***Using context, we can avoid passing props through intermediate elements***
Согласно Реагирующим Документам
Не используйте контекст, чтобы избежать передачи реквизита на несколько уровней. Придерживайтесь случаев, когда одни и те же данные должны быть доступны во многих компонентах на разных уровнях.
Проверьте официальные документы о том, почему и почему не использовать контекст: https://reactjs.org/docs/context.html
Дайте мне знать, если у вас все еще есть проблемы или сомнения относительно того, почему и как использовать контекст