You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 7e25db3
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: contributing/event-dispatch.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -22,7 +22,7 @@ Both are built on the shared event subsystem in `src/events/`, which also holds
22
22
`src/events/fire-event.ts` is the public API. It calls a single handler for a single event, found with `findEventHandler()` from `src/events/propagation.ts`. The work is in finding the right handler:
23
23
24
24
- It starts at the target and moves up the tree until it finds a handler. It also checks props of composite components, not only host elements.
25
-
- Direct events (see [Native event propagation](native-events.md)) only check the target.
25
+
- Direct events (see [Native event propagation](native-events.md)) still bubble, with a warning when they reach an ancestor that emits them. `fireEvent.layout()`only checks the target.
26
26
- It mimics cases where a device would not deliver the event, like `pointerEvents`, a non-editable `TextInput`, or a touch responder that declines.
Copy file name to clipboardExpand all lines: contributing/native-events.md
+19-11Lines changed: 19 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,7 @@
2
2
3
3
In React Native, some events **bubble** up to parent elements and others are **direct**, meaning only the element that emitted them receives them. `fireEvent` should behave the same way.
4
4
5
-
Today, `fireEvent`treats every event as bubbling except `layout`. The list of direct events lives in `isDirectEvent()` in `src/events/propagation.ts`.
5
+
Today, `fireEvent`still bubbles direct events, with a warning (see [Known gaps](#known-gaps)). Only `fireEvent.layout()` does not bubble. The rules live in `isDirectEvent()` in `src/events/propagation.ts`.
6
6
7
7
## Which events are which
8
8
@@ -12,21 +12,29 @@ There is no simple rule for which events bubble. Coming from user input doesn't
This is simplified. A few events differ between iOS and Android. Check the sources below for the exact details.
26
26
27
27
## Known gaps
28
28
29
-
All the direct events above except `layout` still bubble in `fireEvent`. Fixing that is a breaking change: tests that fire these events on a child element would stop reaching the parent's handler.
29
+
`fireEvent` still bubbles the direct events above for backward compatibility, as tests fire them on nested elements, e.g. `scroll` on `ScrollView` content. Making them direct is a breaking change, planned for the next major release, which should also remove the warning.
30
+
31
+
Until then, `fireEvent` logs a warning when a direct event bubbles from a nested element to the handler of an ancestor that emits it, based on the host element type, e.g. `scroll` from `ScrollView` content to the `ScrollView`'s `onScroll`. Handlers with the same name elsewhere, like an `onLoad` prop of a custom composite component, receive bubbled events without a warning. Only the type of the element with the handler is checked, so a handler further up on an element that doesn't emit the event gets no warning, although it will stop receiving the event too.
32
+
33
+
`refresh` is emitted by `RefreshControl`. The Jest `ScrollView` mock renders the `refreshControl` element next to the content view, not around it, so it is never an ancestor of list items. `FlatList` and `SectionList` also pass `onRefresh` to the host `ScrollView`, so the rule uses `ScrollView` as the emitting element.
34
+
35
+
`contentSizeChange` is not a native `ScrollView` event, so the table above doesn't list it. The `ScrollView` component calls `onContentSizeChange` from the `onLayout` of its content view and passes `onContentSizeChange: null` to the host element. The Jest `ScrollView` mock passes the prop to the host element instead, so the rule uses `ScrollView` as the emitting element. `FlatList` and `SectionList` always set this handler, and tests fire the event on list items, so making it direct will break more tests than other events.
36
+
37
+
Both rules depend on the Jest mock. The `FlatList` cases in `src/events/__tests__/fire-event.test.tsx` cover both, so a mock change that moves these handlers fails them.
Copy file name to clipboardExpand all lines: docs/api/fire-event.md
+14-3Lines changed: 14 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,14 +8,25 @@
8
8
> Use Fire Event for cases not supported by User Event and for triggering event handlers on composite components.
9
9
10
10
```ts
11
-
function fireEvent(instance:TestInstance, eventName:string, ...data:unknown[]):Promise<unknown>;
11
+
function fireEvent(instance:TestInstance, eventType:string, ...data:unknown[]):Promise<unknown>;
12
12
```
13
13
14
14
The `fireEvent` API triggers event handlers on both host and composite components. It traverses the component tree bottom-up from the passed element to find an enabled event handler named `onXxx` where `xxx` is the event name.
15
15
16
+
Some events are direct in React Native: they are delivered only to the host element that emitted them. `fireEvent` still bubbles them for backward compatibility, but logs a warning when they bubble from a nested element to the handler of an ancestor that emits them, e.g. `scroll` from `ScrollView` content to the `ScrollView`. They will stop bubbling in the next major version, so fire them on the element that has the handler. These events are:
17
+
18
+
-`layout`, `accessibilityAction`, `accessibilityTap`, `magicTap` and `accessibilityEscape` on all elements
19
+
-`textLayout` on `Text`
20
+
-`scroll`, `selectionChange` and `contentSizeChange` on `TextInput`
21
+
-`loadStart`, `progress`, `partialLoad`, `load`, `error` and `loadEnd` on `Image`
22
+
-`scroll`, `scrollBeginDrag`, `scrollEndDrag`, `momentumScrollBegin`, `momentumScrollEnd`, `scrollToTop`, `refresh` and `contentSizeChange` on `ScrollView`
23
+
-`requestClose`, `show`, `dismiss` and `orientationChange` on `Modal`
24
+
25
+
Events with these names bubble without a warning to other handlers, such as an `onLoad` prop of your own composite component.
26
+
16
27
Unlike User Event, this API does not automatically pass event object to event handler, this is responsibility of the user to construct such object.
17
28
18
-
The base `fireEvent(instance, eventName, ...data)` API can pass multiple custom arguments to the handler. Convenience helpers such as `fireEvent.press` and `fireEvent.scroll` are different: they create a default event object and accept one optional object to merge into it.
29
+
The base `fireEvent(instance, eventType, ...data)` API can pass multiple custom arguments to the handler. Convenience helpers such as `fireEvent.press` and `fireEvent.scroll` are different: they create a default event object and accept one optional object to merge into it.
19
30
20
31
This function uses async `act` internally to execute all pending React updates during event handling.
21
32
@@ -180,7 +191,7 @@ fireEvent.layout: (
180
191
181
192
Builds a layout event carrying the given `layout` rectangle and invokes the `onLayout` handler of the given element. Use it to simulate the layout engine measuring an element, e.g. to test components that adapt to a measured size.
182
193
183
-
Unlike other `fireEvent` calls, layout events do not bubble: React Native delivers them only to the measured element, so the handler is not looked up on parent elements.
194
+
Layout events fired with this helper do not bubble: React Native delivers them only to the measured element, so only that element's own `onLayout` prop is called, not handlers on its parent elements or composite components. This is the intended behavior. `fireEvent(element, 'layout')` still bubbles for backward compatibility, with a deprecation warning, and will stop bubbling like `fireEvent.layout()` in the next major version.
184
195
185
196
The `layout` values are merged onto a zeroed rectangle (`{ x: 0, y: 0, width: 0, height: 0 }`), so pass only the fields your component reads.
Copy file name to clipboardExpand all lines: docs/api/user-event.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,7 @@
2
2
3
3
## Comparison with Fire Event API
4
4
5
-
Fire Event is our original event simulation API. It can invoke **any event handler** declared on **either host or composite elements**. Suppose the element does not have `onEventName` event handler for the passed `eventName` event, or the element is disabled. In that case, Fire Event will traverse up the component tree, looking for an event handler on both host and composite elements along the way. By default, it will **not pass any event data**, but the user might provide it in the last argument.
5
+
Fire Event is our original event simulation API. It can invoke **any event handler** declared on **either host or composite elements**. Suppose the element does not have `onEventName` event handler for the passed `eventType` event, or the element is disabled. In that case, Fire Event will traverse up the component tree, looking for an event handler on both host and composite elements along the way. By default, it will **not pass any event data**, but the user might provide it in the last argument.
6
6
7
7
In contrast, User Event provides realistic event simulation for user interactions like `press` or `type`. Each interaction will trigger a **sequence of events** corresponding to React Native runtime behavior. These events will be invoked **only on host elements**, and **will automatically receive event data** corresponding to each event.
0 commit comments