React-DOM automatically triggering onClick handler

放肆的年华 提交于 2020-03-25 17:51:07

问题


I have a react-modal which shows some filters. It accepts an isOpen prop which hides or shows the Modal as per the value.

The Modal opens successfully when clicked on 'Apply' button, but does not close on clicking 'Cancel'.

//Click Handlers in the parent component (filters.js)
openAllFilters = () => {
  this.setState({ showAllFilters: true });
};

closeAllFilters = () => {
  this.setState({ showAllFilters: false }, () =>
    console.log("state ", this.state.showAllFilters)
  ); // logs true!);
};

<AllFilters isOpen={this.state.showAllFilters}
    closeAllFilters={this.closeAllFilters}
    onRequestClose={this.closeAllFilters}
    renderAbcFilter={this.renderAbcFilter}
    renderDefFilter={this.renderDefFilter}
    renderXyzFilter={this.renderXyzFilter}
/>

The Modal component (AllFilters.js):

import React from 'react';
import Modal from 'react-modal';

const RenderFilter = props => {
    return <div className="filter-wrapper">
        <h3 className="filter-title">{props.title}</h3>
        {props.renderFunction()}
    </div>;
}

const AllFilters = (props) => {
    const modalStyles = {
        overlay: {
            zIndex: 200,
        },
        content: {
            top: '0',
            left: '0',
            right: '0',
            bottom: '0',
            padding: '0',
        }
    };

    return (
        <Modal isOpen={props.isOpen}
            style={modalStyles}
            onRequestClose={props.closeAllFilters}>
            <div className="all-filters-container">
                <RenderFilter title='ABC' renderFunction={() => props.renderAbcFilter(false)} />
                <RenderFilter title='XYZ' renderFunction={() => props.renderXyzFilter(false)} />
                <RenderFilter title='DEF' renderFunction={() => props.renderDefFilter(false)} />
            </div>
            <div className="all-filters-footer">
                <button className="button button-secondary filter-cancel-btn " onClick={props.closeAllFilters}>CANCEL</button>
        </Modal >
    )
}

export default AllFilters;

I can't figure out why state is not updated to false when closeAllFilters is called? EDIT: closeAllFilters does get called when 'Cancel' button is clicked. And console.log(this.state.showAllFilters) outputs true!. Even though this is the setState callback!

EDIT2 : I figured that openAllfilters is somehow automatically getting called after closeAllFilters is invoked. Thus it sets showAllFilters back to true and the modal remains open. Have updated the question title to better reflect the issue. The stack trace for the same is as follows:

openAllFilters (filters.js#382)
callCallback (react-dom.development.js#149)
invokeGuardedCallbackDev (react-dom.development.js#199)
invokeGuardedCallback (react-dom.development.js#256)
invokeGuardedCallbackAndCatchFirstError (react-dom.development.js#270)
executeDispatch (react-dom.development.js#561)
executeDispatchesInOrder (react-dom.development.js#580)
executeDispatchesAndRelease (react-dom.development.js#680)
executeDispatchesAndReleaseTopLevel (react-dom.development.js#688)
forEachAccumulated (react-dom.development.js#662)
runEventsInBatch (react-dom.development.js#816)
runExtractedEventsInBatch (react-dom.development.js#824)
handleTopLevel (react-dom.development.js#4826)
batchedUpdates$1 (react-dom.development.js#20439)
batchedUpdates (react-dom.development.js#2151)
dispatchEvent (react-dom.development.js#4905)
1 (react-dom.development.js#20490)
unstable_runWithPriority (scheduler.development.js#255)
interactiveUpdates$1 (react-dom.development.js#20489)
interactiveUpdates (react-dom.development.js#2170)
dispatchInteractiveEvent (react-dom.development.js#4882)

From above call stack, it seems that React is somehow triggering openAllFilters. I went through these function calls one by one, but still can't figure out why it's happening. Maybe someone who understands React source code well might be able to offer some insight..


回答1:


So after a lot of debugging and head scratching, I finally figured out what the issue was. openAllFilters was getting invoked after call to closeAllFilters due to event propagation. The event is triggered by clicking anywhere on the modal. I didn't find any prop to disable this behaviour, so maybe it's a bug of react-modal. So the only fix required was to add e.stopPropagation()!

So the changed method becomes:

closeAllFilters = (e) => {
    this.setState({ showAllFilters: false });
    e.stopPropagation();
}

Thanks for all the help though!



来源:https://stackoverflow.com/questions/57390304/react-dom-automatically-triggering-onclick-handler

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!