Я пытаюсь обновить состояние своего родительского компонента через дочерний компонент через setState. ниже мой родительский компонент:
Полный
import React from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import Header from '../components/header/header.jsx';
import Customizer from '../components/customizer/customizer';
import { Navbar, NavbarBrand, Collapse } from 'reactstrap';
export const settings = {
navbarbg: 'skin1',
sidebarbg: 'skin6',
logobg: 'skin6'
}
class Fulllayout extends React.Component {
constructor(props) {
super(props);
this.state = {
settings: settings
};
}
render() {
return (
<div id = "main-wrapper">
<header data-navbarbg = {this.state.settings.navbarbg}>
<Navbar expand = "md" className = {}></Navbar>
</header>
<div className = "page-wrapper d-block"></div>
<Customizer />
</div>
);
}
}
export default Fulllayout;
в родительском я определил одну постоянную настройку, которая экспортируется. Он также указан в this.state. а в заголовке есть атрибут data-navbarbg = {this.state.settings.navbarbg}.
Я хотел динамически менять его значение. Итак, у меня есть один настройщик, который импортируется в родительский элемент как дочерний. Ниже представлен дочерний компонент:
настройщик
import React from 'react';
import { settings } from '../../layouts/fulllayout';
import update from 'immutability-helper';
class Customizer extends React.Component {
constructor(props) {
super(props);
this.navbarbgChange = this.navbarbgChange.bind(this);
this.state = {
settings: settings
};
}
navbarbgChange(e) {
var skin = e.currentTarget.dataset.navbarbg;
var abc = update(this.state.settings, {
navbarbg: { $set: skin }
});
this.setState({ settings: abc });
}
render() {
return (
<aside className = "customizer" id = "customizer">
<a className = "service-panel-toggle text-white"></a>
<div className = "customizer-body pt-3">
<div className = "mt-3 border-bottom px-3">
<ul className = "theme-color mb-2">
<li><a data-navbarbg = "skin1" onClick = {this.navbarbgChange}></a></li>
</ul>
</div>
</div>
</aside>
);
}
}
export default Customizer;
Из настройщика, щелкнув цвет, я хотел, чтобы родительский setState соответствовал значению, указанному в атрибуте data-navbarbg.
Если я помещаю этот код в родительский файл jsx, он работает нормально, но по некоторым причинам эти файлы следует хранить отдельно.
Итак, чего не хватает в моем коде? или весь подход неверен? Спасибо.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вы можете вызвать родительский navbarbgChange(e) от ребенка.
в родительском:
navbarbgChange(e) {
var skin = e.currentTarget.dataset.navbarbg;
var abc = update(this.state.settings, {
navbarbg: { $set: skin }
});
this.setState({ settings: abc });
}
<Child parentNavbarbgChange = {navbarbgChange} />
в дочернем вызове в navbarbgChange:
this.props.parentNavbarbgChange(e);
Есть ли причина для определения navbarbgChange в Customizer?
Вместо этого вы можете подумать о переносе navbarbgChange на Fulllayout.
Таким образом вы можете сделать
<li><a data-navbarbg = "skin1" onClick = {this.props.navbarbgChange}></a></li>
Это гарантирует, что Fulllayout будет иметь обновленный фон в своем состоянии. Это также гарантирует хорошее разделение проблем, поскольку settings определен в родительском, а не дочернем компоненте.
В React вы всегда можете передавать методы от родителя к потомку. Давайте напишем метод в родительском элементе, чтобы изменить состояние родителя от дочернего таким образом.
class Fulllayout extends React.Component {
constructor(props) {
super(props);
this.state = {
settings: settings
};
}
// This will be passed to the child component
changeForCustomizerState() {
this.setState({
settings: abc
});
}
changeForHeaderState() {
this.setState({
settings: abc
});
}
render() {
return (
<div id = "main-wrapper">
<header chageNavbarbg = {this.changeForHeaderState}>
<Navbar expand = "md" className = {}></Navbar>
</header>
<div className = "page-wrapper d-block"></div>
<Customizer chageNavbarbg = {this.changeForCustomizerState} />
</div>
);
}
}
Затем onClick для дочернего элемента просто вызывает родительский метод из дочернего элемента, который передается от родителя.
render() {
return (
<aside className = "customizer" id = "customizer">
<a className = "service-panel-toggle text-white"></a>
<div className = "customizer-body pt-3">
<div className = "mt-3 border-bottom px-3">
<ul className = "theme-color mb-2">
<li><a data-navbarbg = "skin1" onClick = {this.props.chageNavbarbg}></a></li>
</ul>
</div>
</div>
</aside>
);
}
Обновление состояния можно выполнить в родительском элементе из дочернего с помощью обратных вызовов. Проверьте код ниже для лучшего понимания
Полная компоновка:
updateState = (skin) => {
this.setState({
settings.navbarbg: skin
});
}
render(){
return(
<div>
<Customizer updateState = {this.updateState}
</div>
);
}
И в вашем настройщике
navbarbgChange(e){
const skin = e.currentTarget.dataset.navbarbg;
this.props.updateState(skin);
}
ИЛИ
Полная компоновка:
updateState = (e) => {
const skin = e.currentTarget.dataset.navbarbg;
this.setState({
settings.navbarbg: skin
});
}
render(){
return(
<div>
<Customizer updateState = {this.updateState}
</div>
);
}
Настройщик: напрямую передать родительскую функцию в onClick
<li><a data-navbarbg = "skin1" onClick = {this.props.updateState}></a></li>
Также прекратите использовать var и начните в основном использовать let и const. Сам ECMASCRIPT утверждает, что следует избегать использования var из-за его области видимости окна.
Этот ответ дал мне правильный подход. Спасибо за это. Но settings.navbarbg: skin выдает неожиданную ошибку токена. Вместо этого я использовал immutability-helper, чтобы он работал, и он работает нормально. Но у меня есть один вопрос. Что делать, если я хочу изменить состояние боковой панели, логотипа и других настроек? Можно ли сделать это только в одной функции?
пожалуйста, не делай этого. это против инкапсуляции. родитель теряет контроль над своим состоянием. это может закончиться проблемами, которые трудно отладить. используйте вместо этого обратный вызов props, они введены именно для этого.