Почему два события щелчка в моем приложении React выполняются одновременно?

#javascript #reactjs #state #jsx #react-props

Вопрос:

У меня есть два варианта пользовательских настроек. Один из них — «включить каскадные панели», а другой — «включить вложения».

Я настроил переменные состояния и функции переключения для передачи дочерним компонентам, чтобы, когда я нажимаю на любой из них, родитель мог переключаться между значениями. Проблема в том, что когда я нажимаю на один из них, другой также выполняется. Неужели я пропустил какой-то шаг в их настройке?

Данные родительского компонента:

Государство:

     constructor(props){
     const userToggleSettings = {
       cascadingPanels: true,
       includeAttachments: true,
       analyticsOptIn: false
     };
    
     this.state = {
       userToggleSettings
     };
    }
 

Переключение функций:

 
toggleIncludeAttachments = () => {
    this.setState((prevState) => (
        {
            userToggleSettings:
            {
                includeAttachments: !prevState.userToggleSettings.includeAttachments
            }
        }
    ));
};

toggleCascadingPanels = () => {
    this.setState((prevState) => (
        {
            userToggleSettings:
            {
                cascadingPanels: !prevState.userToggleSettings.cascadingPanels
            }
        }
    ));
};

includeAttachmentsClickHandler = () => {
    this.toggleIncludeAttachments();
}

cascadingPanelsClickHandler = () => {
    this.toggleCascadingPanels();
}

 

Передача значений и функций в качестве реквизитов:

 <ChildComponent
  attachmentsSwitchHandler={this.toggleIncludeAttachments}
  attachmentsSwitchValue={this.state.userToggleSettings.includeAttachments}
  cascadingPanelsSwitchHandler={this.toggleCascadingPanels}
  cascadingPanelsSwitchValue={this.state.userToggleSettings.cascadingPanels}
/>

 

Данные дочерних компонентов

Настройка событий и значений щелчков в дочернем компоненте:

 <div className='child-component-container'>
    <div className={'user-settings-toggle'}
        onClick={props.cascadingPanelsSwitchHandler}
    >
    <div className={'user-settings-label'}>
            {props.translations.CASCADING_PANELS}
        </div>
    <Switch
        checked={props.cascadingPanelsSwitchValue}
        translations={{
            off: props.translations.off,
            on: props.translations.ON
        }}
        />
    </div>
    <div className={'user-settings-toggle'}
      onClick={props.attachmentsSwitchHandler}
    >
    <Switch
        checked={props.attachmentsSwitchValue}
        translations={{
            off: props.translations.off,
            on: props.translations.ON
        }}
    />
    <div className={'user-settings-label'}>
        {props.translations.ALWAYS_INCLUDE_ATTACHMENTS}
    </div>
</div>
 

ДЕМОНСТРАЦИЯ:

введите описание изображения здесь

Может кто-нибудь прояснить, что я здесь делаю не так?

Ответ №1:

Вы должны изменить свои функции переключения таким образом:

  this.setState((prevState) => (
        {
            userToggleSettings:
            {
                ...prevState.userToggleSettings, // ---> added
                cascadingPanels: !prevState.userToggleSettings.cascadingPanels
            }
        }
    ));
 

React не выполняет «глубокое слияние», т. е. вложенные объекты не объединяются. Объединяются только свойства верхнего уровня.

Таким образом, так, как у вас это было, вы теряли все, что было внутри userToggleSettings объекта, после того, как сделали setState .