Skip to content

Commit

Permalink
[Flare] Tweaks to Flare system design and API (#16264)
Browse files Browse the repository at this point in the history
  • Loading branch information
trueadm authored Aug 1, 2019
1 parent b5af4fe commit 4279455
Show file tree
Hide file tree
Showing 39 changed files with 1,143 additions and 1,193 deletions.
18 changes: 10 additions & 8 deletions packages/react-debug-tools/src/ReactDebugHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type {
ReactContext,
ReactProviderType,
ReactEventResponder,
ReactEventResponderListener,
} from 'shared/ReactTypes';
import type {Fiber} from 'react-reconciler/src/ReactFiber';
import type {Hook} from 'react-reconciler/src/ReactFiberHooks';
Expand All @@ -25,8 +26,6 @@ import {
ForwardRef,
} from 'shared/ReactWorkTags';

const emptyObject = {};

type CurrentDispatcherRef = typeof ReactSharedInternals.ReactCurrentDispatcher;

// Used to track hooks called during a render
Expand Down Expand Up @@ -221,17 +220,20 @@ function useMemo<T>(
return value;
}

function useListener(
function useResponder(
responder: ReactEventResponder<any, any>,
hookProps: ?Object,
): void {
const listenerProps = hookProps || emptyObject;
listenerProps: Object,
): ReactEventResponderListener<any, any> {
// Don't put the actual event responder object in, just its displayName
const value = {
responder: responder.displayName || 'EventResponder',
props: listenerProps,
};
hookLog.push({primitive: 'Listener', stackError: new Error(), value});
hookLog.push({primitive: 'Responder', stackError: new Error(), value});
return {
responder,
props: listenerProps,
};
}

const Dispatcher: DispatcherType = {
Expand All @@ -246,7 +248,7 @@ const Dispatcher: DispatcherType = {
useReducer,
useRef,
useState,
useListener,
useResponder,
};

// Inspect
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,21 @@ describe('ReactHooksInspection', () => {
ReactDebugTools = require('react-debug-tools');
});

it('should inspect a simple useListener hook', () => {
it('should inspect a simple useResponder hook', () => {
const TestResponder = React.unstable_createResponder('TestResponder', {});

function Foo(props) {
React.unstable_useListener(TestResponder, {preventDefault: false});
return <div responders={<TestResponder />}>Hello world</div>;
const listener = React.unstable_useResponder(TestResponder, {
preventDefault: false,
});
return <div listeners={listener}>Hello world</div>;
}
let tree = ReactDebugTools.inspectHooks(Foo, {});
expect(tree).toEqual([
{
isStateEditable: false,
id: 0,
name: 'Listener',
name: 'Responder',
value: {props: {preventDefault: false}, responder: 'TestResponder'},
subHooks: [],
},
Expand Down
10 changes: 5 additions & 5 deletions packages/react-dom/src/client/ReactDOMComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ const AUTOFOCUS = 'autoFocus';
const CHILDREN = 'children';
const STYLE = 'style';
const HTML = '__html';
const RESPONDERS = 'responders';
const LISTENERS = 'listeners';

const {html: HTML_NAMESPACE} = Namespaces;

Expand Down Expand Up @@ -341,7 +341,7 @@ function setInitialDOMProperties(
setTextContent(domElement, '' + nextProp);
}
} else if (
(enableFlareAPI && propKey === RESPONDERS) ||
(enableFlareAPI && propKey === LISTENERS) ||
propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
propKey === SUPPRESS_HYDRATION_WARNING
) {
Expand Down Expand Up @@ -698,7 +698,7 @@ export function diffProperties(
} else if (propKey === DANGEROUSLY_SET_INNER_HTML || propKey === CHILDREN) {
// Noop. This is handled by the clear text mechanism.
} else if (
(enableFlareAPI && propKey === RESPONDERS) ||
(enableFlareAPI && propKey === LISTENERS) ||
propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
propKey === SUPPRESS_HYDRATION_WARNING
) {
Expand Down Expand Up @@ -790,7 +790,7 @@ export function diffProperties(
(updatePayload = updatePayload || []).push(propKey, '' + nextProp);
}
} else if (
(enableFlareAPI && propKey === RESPONDERS) ||
(enableFlareAPI && propKey === LISTENERS) ||
propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
propKey === SUPPRESS_HYDRATION_WARNING
) {
Expand Down Expand Up @@ -1045,7 +1045,7 @@ export function diffHydratedProperties(
if (suppressHydrationWarning) {
// Don't bother comparing. We're ignoring all these warnings.
} else if (
(enableFlareAPI && propKey === RESPONDERS) ||
(enableFlareAPI && propKey === LISTENERS) ||
propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
propKey === SUPPRESS_HYDRATION_WARNING ||
// Controlled attributes are not validated
Expand Down
96 changes: 13 additions & 83 deletions packages/react-dom/src/events/DOMEventResponderSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,7 @@ import {
PASSIVE_NOT_SUPPORTED,
} from 'events/EventSystemFlags';
import type {AnyNativeEvent} from 'events/PluginModuleType';
import {
HostComponent,
FunctionComponent,
MemoComponent,
ForwardRef,
} from 'shared/ReactWorkTags';
import {HostComponent} from 'shared/ReactWorkTags';
import type {EventPriority} from 'shared/ReactTypes';
import type {
ReactDOMEventResponder,
Expand Down Expand Up @@ -67,7 +62,7 @@ export function setListenToResponderEventTypes(
}

type EventQueueItem = {|
listeners: Array<(val: any) => void>,
listener: (val: any) => void,
value: any,
|};
type EventQueue = Array<EventQueueItem>;
Expand Down Expand Up @@ -103,24 +98,18 @@ let currentDocument: null | Document = null;

const eventResponderContext: ReactDOMResponderContext = {
dispatchEvent(
eventProp: string,
eventValue: any,
eventListener: any => void,
eventPriority: EventPriority,
): void {
validateResponderContext();
validateEventValue(eventValue);
if (eventPriority < currentEventQueuePriority) {
currentEventQueuePriority = eventPriority;
}
const responderInstance = ((currentInstance: any): ReactDOMEventResponderInstance);
const target = responderInstance.fiber;
const responder = responderInstance.responder;
const listeners = collectListeners(eventProp, responder, target);
if (listeners.length !== 0) {
((currentEventQueue: any): EventQueue).push(
createEventQueueItem(eventValue, listeners),
);
}
((currentEventQueue: any): EventQueue).push(
createEventQueueItem(eventValue, eventListener),
);
},
isTargetWithinResponder(target: Element | Document): boolean {
validateResponderContext();
Expand Down Expand Up @@ -392,11 +381,11 @@ function collectFocusableElements(

function createEventQueueItem(
value: any,
listeners: Array<(val: any) => void>,
listener: (val: any) => void,
): EventQueueItem {
return {
value,
listeners,
listener,
};
}

Expand Down Expand Up @@ -519,70 +508,11 @@ function createDOMResponderEvent(
};
}

function collectListeners(
eventProp: string,
eventResponder: ReactDOMEventResponder,
target: Fiber,
): Array<(any) => void> {
const eventListeners = [];
let node = target.return;
nodeTraversal: while (node !== null) {
switch (node.tag) {
case HostComponent: {
const dependencies = node.dependencies;

if (dependencies !== null) {
const respondersMap = dependencies.responders;

if (respondersMap !== null && respondersMap.has(eventResponder)) {
break nodeTraversal;
}
}
break;
}
case FunctionComponent:
case MemoComponent:
case ForwardRef: {
const dependencies = node.dependencies;

if (dependencies !== null) {
const listeners = dependencies.listeners;

if (listeners !== null) {
for (
let s = 0, listenersLength = listeners.length;
s < listenersLength;
s++
) {
const listener = listeners[s];
const {responder, props} = listener;
const listenerFunc = props[eventProp];

if (
responder === eventResponder &&
typeof listenerFunc === 'function'
) {
eventListeners.push(listenerFunc);
}
}
}
}
}
}
node = node.return;
}
return eventListeners;
}

function processEvents(eventQueue: EventQueue): void {
for (let i = 0, length = eventQueue.length; i < length; i++) {
const {value, listeners} = eventQueue[i];
for (let s = 0, length2 = listeners.length; s < length2; s++) {
const listener = listeners[s];
const type =
typeof value === 'object' && value !== null ? value.type : '';
invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, value);
}
const {value, listener} = eventQueue[i];
const type = typeof value === 'object' && value !== null ? value.type : '';
invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, value);
}
}

Expand Down Expand Up @@ -663,14 +593,14 @@ function traverseAndHandleEventResponderInstances(
// - Bubble target responder phase
// - Root responder phase

const visitedResponders = new Set();
const responderEvent = createDOMResponderEvent(
topLevelType,
nativeEvent,
nativeEventTarget,
isPassiveEvent,
isPassiveSupported,
);
const visitedResponders = new Set();
let node = targetFiber;
while (node !== null) {
const {dependencies, tag} = node;
Expand All @@ -687,8 +617,8 @@ function traverseAndHandleEventResponderInstances(
!visitedResponders.has(responder) &&
validateResponderTargetEventTypes(eventType, responder)
) {
const onEvent = responder.onEvent;
visitedResponders.add(responder);
const onEvent = responder.onEvent;
if (onEvent !== null) {
currentInstance = responderInstance;
responderEvent.responderTarget = ((target: any):
Expand Down
Loading

0 comments on commit 4279455

Please sign in to comment.