/
githubmr
/
facebook-react
Обзор
Документация
Войти
/
githubmr
/
facebook-react
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
main
packages/react-native-renderer/src/legacy-events/SyntheticEvent.js
347 строк
9 KB
Ricky
Update /link URLs to react.dev (#28477)
04 мар 2024, 01:34
Не верифицирован
04 мар 2024, 01:34
1940cb2
Код
Авторство
О чём код?
/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ /* eslint valid-typeof: 0 */ import assign from 'shared/assign'; const EVENT_POOL_SIZE = 10; /** * @interface Event * @see http://www.w3.org/TR/DOM-Level-3-Events/ */ const EventInterface = { type: null, target: null, // currentTarget is set when dispatching; no use in copying it here currentTarget: function () { return null; }, eventPhase: null, bubbles: null, cancelable: null, timeStamp: function (event) { return event.timeStamp || Date.now(); }, defaultPrevented: null, isTrusted: null, }; function functionThatReturnsTrue() { return true; } function functionThatReturnsFalse() { return false; } /** * Synthetic events are dispatched by event plugins, typically in response to a * top-level event delegation handler. * * These systems should generally use pooling to reduce the frequency of garbage * collection. The system should check `isPersistent` to determine whether the * event should be released into the pool after being dispatched. Users that * need a persisted event should invoke `persist`. * * Synthetic events (and subclasses) implement the DOM Level 3 Events API by * normalizing browser quirks. Subclasses do not necessarily have to implement a * DOM interface; custom application-specific events can also subclass this. * * @param {object} dispatchConfig Configuration used to dispatch this event. * @param {*} targetInst Marker identifying the event target. * @param {object} nativeEvent Native browser event. * @param {DOMEventTarget} nativeEventTarget Target node. */ function SyntheticEvent( dispatchConfig, targetInst, nativeEvent, nativeEventTarget, ) { if (__DEV__) { // these have a getter/setter for warnings delete this.nativeEvent; delete this.preventDefault; delete this.stopPropagation; delete this.isDefaultPrevented; delete this.isPropagationStopped; } this.dispatchConfig = dispatchConfig; this._targetInst = targetInst; this.nativeEvent = nativeEvent; this._dispatchListeners = null; this._dispatchInstances = null; const Interface = this.constructor.Interface; for (const propName in Interface) { if (!Interface.hasOwnProperty(propName)) { continue; } if (__DEV__) { delete this[propName]; // this has a getter/setter for warnings } const normalize = Interface[propName]; if (normalize) { this[propName] = normalize(nativeEvent); } else { if (propName === 'target') { this.target = nativeEventTarget; } else { this[propName] = nativeEvent[propName]; } } } const defaultPrevented = nativeEvent.defaultPrevented != null ? nativeEvent.defaultPrevented : nativeEvent.returnValue === false; if (defaultPrevented) { this.isDefaultPrevented = functionThatReturnsTrue; } else { this.isDefaultPrevented = functionThatReturnsFalse; } this.isPropagationStopped = functionThatReturnsFalse; return this; } assign(SyntheticEvent.prototype, { preventDefault: function () { this.defaultPrevented = true; const event = this.nativeEvent; if (!event) { return; } if (event.preventDefault) { event.preventDefault(); } else if (typeof event.returnValue !== 'unknown') { event.returnValue = false; } this.isDefaultPrevented = functionThatReturnsTrue; }, stopPropagation: function () { const event = this.nativeEvent; if (!event) { return; } if (event.stopPropagation) { event.stopPropagation(); } else if (typeof event.cancelBubble !== 'unknown') { // The ChangeEventPlugin registers a "propertychange" event for // IE. This event does not support bubbling or cancelling, and // any references to cancelBubble throw "Member not found". A // typeof check of "unknown" circumvents this issue (and is also // IE specific). event.cancelBubble = true; } this.isPropagationStopped = functionThatReturnsTrue; }, /** * We release all dispatched `SyntheticEvent`s after each event loop, adding * them back into the pool. This allows a way to hold onto a reference that * won't be added back into the pool. */ persist: function () { this.isPersistent = functionThatReturnsTrue; }, /** * Checks if this event should be released back into the pool. * * @return {boolean} True if this should not be released, false otherwise. */ isPersistent: functionThatReturnsFalse, /** * `PooledClass` looks for `destructor` on each instance it releases. */ destructor: function () { const Interface = this.constructor.Interface; for (const propName in Interface) { if (__DEV__) { Object.defineProperty( this, propName, getPooledWarningPropertyDefinition(propName, Interface[propName]), ); } else { this[propName] = null; } } this.dispatchConfig = null; this._targetInst = null; this.nativeEvent = null; this.isDefaultPrevented = functionThatReturnsFalse; this.isPropagationStopped = functionThatReturnsFalse; this._dispatchListeners = null; this._dispatchInstances = null; if (__DEV__) { Object.defineProperty( this, 'nativeEvent', getPooledWarningPropertyDefinition('nativeEvent', null), ); Object.defineProperty( this, 'isDefaultPrevented', getPooledWarningPropertyDefinition( 'isDefaultPrevented', functionThatReturnsFalse, ), ); Object.defineProperty( this, 'isPropagationStopped', getPooledWarningPropertyDefinition( 'isPropagationStopped', functionThatReturnsFalse, ), ); Object.defineProperty( this, 'preventDefault', getPooledWarningPropertyDefinition('preventDefault', () => {}), ); Object.defineProperty( this, 'stopPropagation', getPooledWarningPropertyDefinition('stopPropagation', () => {}), ); } }, }); SyntheticEvent.Interface = EventInterface; /** * Helper to reduce boilerplate when creating subclasses. */ SyntheticEvent.extend = function (Interface) { const Super = this; const E = function () {}; E.prototype = Super.prototype; const prototype = new E(); function Class() { return Super.apply(this, arguments); } assign(prototype, Class.prototype); Class.prototype = prototype; Class.prototype.constructor = Class; Class.Interface = assign({}, Super.Interface, Interface); Class.extend = Super.extend; addEventPoolingTo(Class); return Class; }; addEventPoolingTo(SyntheticEvent); /** * Helper to nullify syntheticEvent instance properties when destructing * * @param {String} propName * @param {?object} getVal * @return {object} defineProperty object */ function getPooledWarningPropertyDefinition(propName, getVal) { function set(val) { const action = isFunction ? 'setting the method' : 'setting the property'; warn(action, 'This is effectively a no-op'); return val; } function get() { const action = isFunction ? 'accessing the method' : 'accessing the property'; const result = isFunction ? 'This is a no-op function' : 'This is set to null'; warn(action, result); return getVal; } function warn(action, result) { if (__DEV__) { console.error( "This synthetic event is reused for performance reasons. If you're seeing this, " + "you're %s `%s` on a released/nullified synthetic event. %s. " + 'If you must keep the original synthetic event around, use event.persist(). ' + 'See https://react.dev/link/event-pooling for more information.', action, propName, result, ); } } const isFunction = typeof getVal === 'function'; return { configurable: true, set: set, get: get, }; } function createOrGetPooledEvent( dispatchConfig, targetInst, nativeEvent, nativeInst, ) { const EventConstructor = this; if (EventConstructor.eventPool.length) { const instance = EventConstructor.eventPool.pop(); EventConstructor.call( instance, dispatchConfig, targetInst, nativeEvent, nativeInst, ); return instance; } return new EventConstructor( dispatchConfig, targetInst, nativeEvent, nativeInst, ); } function releasePooledEvent(event) { const EventConstructor = this; if (!(event instanceof EventConstructor)) { throw new Error( 'Trying to release an event instance into a pool of a different type.', ); } event.destructor(); if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) { EventConstructor.eventPool.push(event); } } function addEventPoolingTo(EventConstructor) { EventConstructor.getPooled = createOrGetPooledEvent; EventConstructor.eventPool = []; EventConstructor.release = releasePooledEvent; } export default SyntheticEvent;