-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC] Use event.defaultMuiPrevented to prevent default events #1403
Comments
To solve 3 & 5 you can use a capture event. https://codesandbox.io/s/material-demo-forked-3mhuk?file=/demo.js |
@oliviertassinari Could you detail which callbacks you refer in 5? I'm not sure if I understood the problem. Do you mean that |
@m4theushw Yeah, I wasn't very clear. My point assumed too much context.
However, in order to make
To be honest, I have never seen a real issue with the reversal of the call order. But on paper, it's not sounds, so be careful, there are mutations done in each handler. It's more a theoretical concern than a practical one. |
for 3., the first listener is always |
@dtassone Yes, this is the problem I'm describing, in theory, it shouldn't. |
All event handlers registered in the This seems to me similar to the old React lifecycle callbacks: |
@m4theushw I would personally advocate for ignoring 5. if the solution it requires is too heavy, the downside is limited. |
We also control a part of the publication of events as apiRef is based on ATM. if |
some more thoughts.
|
|
For 1. there is a small distinction here, that I was trying to explain. However for events that are specific to the grid such as 'cellClick' or |
Regarding the TypeScript downside of this proposal. I personally think that a |
There might be a third way to solve this problem, a stateReducer which would allow developers to make the events they are interested in as no-op. However, it would require refactoring the update of the state to attach them corresponding event names. |
@m4theushw, @flaviendelangle Are we happy to move forward with: If my issue description is not enough, see for another example of why #2146 (comment). It's potentially a breaking change if we drop custom logic for (event.stopPropagation). We don't have to do it now, we could do it later on, in the next major. |
I'm happy to adopt onCellFocusOut?: (params: GridCellParams, originalEvent?: React.SyntheticEvent, event: MuiEvent<MouseEvent>) => void; The third event is the one that we check for The problem with the |
@m4theushw Interesting. Two thoughts:
|
I'm thinking about how we can implement 1. Taking as example #2146 (comment):
I want to cancel About 2. could you elaborate more your proposal? Is about wrapping the event? It has to work both with synthetic events and native events. |
for option 1. I had this reset in mind. When the grid fires a new event, we make sure it's pristine. diff --git a/packages/grid/_modules_/grid/hooks/root/useApi.ts b/packages/grid/_modules_/grid/hooks/root/useApi.ts
index 91637e88..8041c29d 100644
--- a/packages/grid/_modules_/grid/hooks/root/useApi.ts
+++ b/packages/grid/_modules_/grid/hooks/root/useApi.ts
@@ -11,6 +11,9 @@ export function useApi(apiRef: GridApiRef): void {
const publishEvent = React.useCallback(
(name: string, params: any, event?: React.SyntheticEvent) => {
if (!event || !event.isPropagationStopped || !event.isPropagationStopped()) {
+ if (event) {
+ event.defaultMuiPrevented = false;
+ }
apiRef.current.emit(name, params, event);
}
}, for option 2. I guess I didn't get how it would work in practice. I didn't get how we could have a unique for option 3 (the alternative to 2 that you made me think of). The concept is simply to recognize that we use the event as a vector to cancel the handles of the grid. We could use a custom data structure to do it too. As a side note, the current handling of .defaultMuiPrevented and isPropagationStopped is not great. AFAIK, we don't need to repeat the exit branch logic in each handler. Instead, we could move the logic at the |
I liked this option 1. About the potential issue I raised with promises, I don't think we have to worry. If the developer cancels the default behavior outside the promise it will work. We can extend the export type MuiEvent<T extends keyof GlobalEventHandlersEventMap> = (
| GlobalEventHandlersEventMap[T]
| React.SyntheticEvent
) & {
defaultMuiPrevented?: boolean;
};
Some events are published without the event argument. Even when there's no subscriber listening to them, for consistency, we have to provide a default one. |
Summary 💡
This RFC highlights issues with the current solution and explores an alternative with fewer drawbacks. The conversation started with #1381.
Motivation 🔦
The cell edit feature is soon to be released with the introduction of a new concept:
event.stopPropagation()
as a means to prevent the default behavior of the component.https://github.com/mui-org/material-ui-x/blob/ca286ad1aa388a7ee8b6cb3609124f583679a45d/packages/grid/x-grid/src/tests/events.XGrid.test.tsx#L221-L230
I would like to highlight 5 important problems that the approach creates (before we release it).
event.stopPropagation()
in the DOM and React stops the bubbling of the event to the parents but has no impacts on the element it listens to. It keeps calling the other listeners on the currentTarget element. In order to stop the other listeners to trigger on the same element, developers have to useevent.stopImmediatePropagation
in the DOM, which doesn't exist in the React realm.event.stopPropagation()
only works for events that are React synthetic events. The approach doesn't work on DOM events because there are no equivalents toevent.defaultPrevented
like React has (event.isPropagationStopped). So we can't scale the solution to all our use cases.event.stopPropagation()
stops the bubbling of the event. Meaning, if you want to handle the event on the parent, but still want to prevent the default behavior. You can't, you are screwed. Proof: https://codesandbox.io/s/material-demo-forked-1sstp?file=/demo.js. This is why it's commonly considered a practice to void. I agree that calling stopPropagation on the events the data grid is going to use for the cell editing makes sense, it's only when we want to disable the feature that it doesn't make any sense.Proposed Solution 🧾
We can solve 1. 2. 3. and 4. by using the approach used in the core. The only downside it has I'm aware of with this solution is 5. I actually think that the discussion should be reversed. Why is the solution in the core not good enough that it prevents being applied in the data grid component?
Unresolved Questions ❓
I have no idea how we could come up with a solution that also resolves 5.
The text was updated successfully, but these errors were encountered: