Experimental event API: Support EventComponent onUnmount responder callback (#15335)

This commit is contained in:
Dominic Gannaway
2019-04-06 08:16:57 +01:00
committed by GitHub
parent 4fbbae8afa
commit 4064ea9fa6
13 changed files with 122 additions and 8 deletions
+7
View File
@@ -442,6 +442,13 @@ export function unhideTextInstance(textInstance, text): void {
export function handleEventComponent(
eventResponder: ReactEventResponder,
rootContainerInstance: Container,
) {
throw new Error('Not yet implemented.');
}
export function unmountEventComponent(
eventResponder: ReactEventResponder,
rootContainerInstance: Container,
internalInstanceHandle: Object,
): void {
throw new Error('Not yet implemented.');
+12 -1
View File
@@ -45,6 +45,7 @@ import dangerousStyleValue from '../shared/dangerousStyleValue';
import type {DOMContainer} from './ReactDOM';
import type {ReactEventResponder} from 'shared/ReactTypes';
import {unmountEventResponder} from '../events/DOMEventResponderSystem';
import {REACT_EVENT_TARGET_TOUCH_HIT} from 'shared/ReactSymbols';
import {canUseDOM} from 'shared/ExecutionEnvironment';
@@ -890,7 +891,6 @@ export function didNotFindHydratableSuspenseInstance(
export function handleEventComponent(
eventResponder: ReactEventResponder,
rootContainerInstance: Container,
internalInstanceHandle: Object,
): void {
if (enableEventAPI) {
const rootElement = rootContainerInstance.ownerDocument;
@@ -901,6 +901,17 @@ export function handleEventComponent(
}
}
export function unmountEventComponent(
eventResponder: ReactEventResponder,
rootContainerInstance: Container,
internalInstanceHandle: Object,
): void {
if (enableEventAPI) {
// TODO stop listening to targetEventTypes
unmountEventResponder(eventResponder, internalInstanceHandle);
}
}
export function getEventTargetChildElement(
type: Symbol | number,
props: Props,
+35 -1
View File
@@ -364,10 +364,17 @@ function handleTopLevelType(
if (state === null && responder.createInitialState !== undefined) {
state = fiber.stateNode.state = responder.createInitialState(props);
}
const previousFiber = currentFiber;
const previousResponder = currentResponder;
currentFiber = fiber;
currentResponder = responder;
responder.onEvent(responderEvent, eventResponderContext, props, state);
try {
responder.onEvent(responderEvent, eventResponderContext, props, state);
} finally {
currentFiber = previousFiber;
currentResponder = previousResponder;
}
}
export function runResponderEventsInBatch(
@@ -413,3 +420,30 @@ export function runResponderEventsInBatch(
processEventQueue();
}
}
export function unmountEventResponder(
responder: ReactEventResponder,
fiber: Fiber,
): void {
const onUnmount = responder.onUnmount;
if (onUnmount !== undefined) {
let {props, state} = fiber.stateNode;
const previousEventQueue = currentEventQueue;
const previousFiber = currentFiber;
const previousResponder = currentResponder;
currentEventQueue = createEventQueue();
currentFiber = fiber;
currentResponder = responder;
try {
onUnmount(eventResponderContext, props, state);
} finally {
currentEventQueue = previousEventQueue;
currentFiber = previousFiber;
currentResponder = previousResponder;
}
}
if (currentOwner === fiber) {
// TODO fire owner changed callback
currentOwner = null;
}
}
@@ -13,10 +13,11 @@ let React;
let ReactFeatureFlags;
let ReactDOM;
function createReactEventComponent(targetEventTypes, onEvent) {
function createReactEventComponent(targetEventTypes, onEvent, onUnmount) {
const testEventResponder = {
targetEventTypes,
onEvent,
onUnmount,
};
return {
@@ -316,4 +317,26 @@ describe('DOMEventResponderSystem', () => {
expect(eventLog).toEqual(['press', 'longpress', 'longpresschange']);
});
it('the event responder onUnmount() function should fire', () => {
let onUnmountFired = 0;
const EventComponent = createReactEventComponent(
[],
(event, context, props) => {},
() => {
onUnmountFired++;
},
);
const Test = () => (
<EventComponent>
<button />
</EventComponent>
);
ReactDOM.render(<Test />, container);
ReactDOM.render(null, container);
expect(onUnmountFired).toEqual(1);
});
});
+1 -1
View File
@@ -209,6 +209,7 @@ function unmountResponder(
): void {
if (state.isPressed) {
state.isPressed = false;
context.removeRootEventTypes(rootEventTypes);
dispatchPressEndEvents(context, props, state);
if (state.longPressTimeout !== null) {
clearTimeout(state.longPressTimeout);
@@ -429,7 +430,6 @@ const PressResponder = {
}
}
},
// TODO This method doesn't work as of yet
onUnmount(context: ResponderContext, props: PressProps, state: PressState) {
unmountResponder(context, props, state);
},
@@ -437,6 +437,13 @@ export function replaceContainerChildren(
export function handleEventComponent(
eventResponder: ReactEventResponder,
rootContainerInstance: Container,
) {
throw new Error('Not yet implemented.');
}
export function unmountEventComponent(
eventResponder: ReactEventResponder,
rootContainerInstance: Container,
internalInstanceHandle: Object,
): void {
throw new Error('Not yet implemented.');
@@ -496,11 +496,18 @@ export function unhideTextInstance(
export function handleEventComponent(
eventResponder: ReactEventResponder,
rootContainerInstance: Container,
internalInstanceHandle: Object,
) {
throw new Error('Not yet implemented.');
}
export function unmountEventComponent(
eventResponder: ReactEventResponder,
rootContainerInstance: Container,
internalInstanceHandle: Object,
): void {
throw new Error('Not yet implemented.');
}
export function getEventTargetChildElement(
type: Symbol | number,
props: Props,
+5 -1
View File
@@ -431,7 +431,11 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
isPrimaryRenderer: true,
supportsHydration: false,
handleEventComponent() {
handleEventComponent(): void {
// NO-OP
},
unmountEventComponent(): void {
// NO-OP
},
+1
View File
@@ -626,6 +626,7 @@ export function createFiberFromEventComponent(
fiber.stateNode = {
context: null,
props: pendingProps,
rootInstance: null,
state: null,
};
fiber.expirationTime = expirationTime;
+10
View File
@@ -44,6 +44,7 @@ import {
IncompleteClassComponent,
MemoComponent,
SimpleMemoComponent,
EventComponent,
EventTarget,
} from 'shared/ReactWorkTags';
import {
@@ -92,6 +93,7 @@ import {
hideTextInstance,
unhideInstance,
unhideTextInstance,
unmountEventComponent,
commitEventTarget,
} from './ReactFiberHostConfig';
import {
@@ -745,6 +747,14 @@ function commitUnmount(current: Fiber): void {
}
return;
}
case EventComponent: {
if (enableEventAPI) {
const rootContainerInstance = current.stateNode.rootInstance;
const responder = current.type.responder;
unmountEventComponent(responder, rootContainerInstance, current);
current.stateNode = null;
}
}
}
}
+3 -1
View File
@@ -776,7 +776,9 @@ function completeWork(
const responder = workInProgress.type.responder;
// Update the props on the event component state node
workInProgress.stateNode.props = newProps;
handleEventComponent(responder, rootContainerInstance, workInProgress);
// Update the root container, so we can properly unmount events at some point
workInProgress.stateNode.rootInstance = rootContainerInstance;
handleEventComponent(responder, rootContainerInstance);
}
break;
}
@@ -86,6 +86,7 @@ export const hideInstance = $$$hostConfig.hideInstance;
export const hideTextInstance = $$$hostConfig.hideTextInstance;
export const unhideInstance = $$$hostConfig.unhideInstance;
export const unhideTextInstance = $$$hostConfig.unhideTextInstance;
export const unmountEventComponent = $$$hostConfig.unmountEventComponent;
export const commitTouchHitTargetUpdate =
$$$hostConfig.commitTouchHitTargetUpdate;
export const commitEventTarget = $$$hostConfig.commitEventTarget;
+8 -1
View File
@@ -330,7 +330,6 @@ export function unhideTextInstance(
export function handleEventComponent(
eventResponder: ReactEventResponder,
rootContainerInstance: Container,
internalInstanceHandle: Object,
): void {
// noop
}
@@ -364,6 +363,14 @@ export function getEventTargetChildElement(
return null;
}
export function unmountEventComponent(
eventResponder: ReactEventResponder,
rootContainerInstance: Container,
internalInstanceHandle: Object,
): void {
// TODO: add unmountEventComponent implementation
}
export function handleEventTarget(
type: Symbol | number,
props: Props,