Reactjs: как обновить состояние родителя от ребенка

Я пытаюсь обновить состояние своего родительского компонента через дочерний компонент через 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, он работает нормально, но по некоторым причинам эти файлы следует хранить отдельно.

Итак, чего не хватает в моем коде? или весь подход неверен? Спасибо.

Поведение ключевого слова "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) для оценки ваших знаний,...
1
0
121
4

Ответы 4

Вы можете вызвать родительский 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);

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

skyboyer 08.09.2018 13:05

Есть ли причина для определения 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, чтобы он работал, и он работает нормально. Но у меня есть один вопрос. Что делать, если я хочу изменить состояние боковой панели, логотипа и других настроек? Можно ли сделать это только в одной функции?

Vishal Bhatt 09.09.2018 13:41

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