Home > Net >  Why do my two click events in my React app run at the same time?
Why do my two click events in my React app run at the same time?

Time:10-15

I have two user settings options. One is "enable cascading panels", and the other is "include attachments".

I have set up state variables and toggle functions to pass down to the child components so that when I click on either, the parent is able to toggle between the values. The issue is that when I click on either, the other one executes as well. Did I miss a step in setting these up?

Parent component data:

State:

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

Toggle functions:


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

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

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

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

Passing values and functions as props:

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

Child component data

Setting up click events and values in child component:

<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>

Demo:

enter image description here

Could someone clarify what I am doing wrong here?

CodePudding user response:

You should change your toggle functions in such way:

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

React doesn't perform a "deep merge", i.e. the nested objects are not merged. Only top level properties are merged.

So the way you had it you were losing whatever was there inside the userToggleSettings object, after doing setState.

  • Related