@@ -17,8 +17,13 @@ import type {ExpirationTime} from './ReactFiberExpirationTime';
1717import type { HookEffectTag } from './ReactHookEffectTags' ;
1818import type { SuspenseConfig } from './ReactFiberSuspenseConfig' ;
1919import type { ReactPriorityLevel } from './SchedulerWithReactIntegration' ;
20+ import type {
21+ ReactListenerEvent ,
22+ ReactListenerMap ,
23+ } from './ReactFiberHostConfig' ;
2024
2125import ReactSharedInternals from 'shared/ReactSharedInternals' ;
26+ import { enableUseEventAPI } from 'shared/ReactFeatureFlags' ;
2227
2328import { NoWork , Sync } from './ReactFiberExpirationTime' ;
2429import { readContext } from './ReactFiberNewContext' ;
@@ -28,6 +33,7 @@ import {
2833 Passive as PassiveEffect ,
2934} from 'shared/ReactSideEffectTags' ;
3035import {
36+ NoEffect as NoHookEffect ,
3137 HasEffect as HookHasEffect ,
3238 Layout as HookLayout ,
3339 Passive as HookPassive ,
@@ -97,6 +103,7 @@ export type Dispatcher = {|
97103 useTransition (
98104 config : SuspenseConfig | void | null ,
99105 ) : [ ( ( ) => void ) => void , boolean ] ,
106+ useEvent ( event : ReactListenerEvent ) : ReactListenerMap ,
100107| } ;
101108
102109type Update < S , A > = { |
@@ -129,7 +136,8 @@ export type HookType =
129136 | 'useDebugValue'
130137 | 'useResponder'
131138 | 'useDeferredValue'
132- | 'useTransition ';
139+ | 'useTransition'
140+ | 'useEvent' ;
133141
134142let didWarnAboutMismatchedHooksForComponent ;
135143if ( __DEV__ ) {
@@ -1369,6 +1377,77 @@ function dispatchAction<S, A>(
13691377 }
13701378}
13711379
1380+ const noOpMount = ( ) => { } ;
1381+
1382+ function mountEventListener(event: ReactListenerEvent): ReactListenerMap {
1383+ if ( enableUseEventAPI ) {
1384+ const hook = mountWorkInProgressHook ( ) ;
1385+
1386+ const clear = ( ) => {
1387+ // TODO
1388+ } ;
1389+
1390+ const reactListenerMap : ReactListenerMap = {
1391+ clear,
1392+ setListener ( instance : EventTarget , callback : ?( Event ) => void ) : void {
1393+ // TODO
1394+ } ,
1395+ } ;
1396+ // In order to clear up upon the hook unmounting,
1397+ // we ensure we set the effecrt tag so that we visit
1398+ // this effect in the commit phase, so we can handle
1399+ // clean-up accordingly.
1400+ currentlyRenderingFiber . effectTag |= UpdateEffect ;
1401+ pushEffect ( NoHookEffect , noOpMount , clear , null ) ;
1402+ hook . memoizedState = [ reactListenerMap , event , clear ] ;
1403+ return reactListenerMap ;
1404+ }
1405+ // To make Flow not complain
1406+ return (undefined: any);
1407+ }
1408+
1409+ function updateEventListener ( event : ReactListenerEvent ) : ReactListenerMap {
1410+ if ( enableUseEventAPI ) {
1411+ const hook = updateWorkInProgressHook ( ) ;
1412+ const [ reactListenerMap , memoizedEvent , clear ] = hook . memoizedState ;
1413+ if ( __DEV__ ) {
1414+ if ( memoizedEvent . type !== event . type ) {
1415+ console . warn (
1416+ 'The event type argument passed to the useEvent() hook was different between renders.' +
1417+ ' The event type is static and should never change between renders.' ,
1418+ ) ;
1419+ }
1420+ if (memoizedEvent.capture !== event.capture) {
1421+ console . warn (
1422+ 'The "capture" option passed to the useEvent() hook was different between renders.' +
1423+ ' The "capture" option is static and should never change between renders.' ,
1424+ ) ;
1425+ }
1426+ if (memoizedEvent.priority !== event.priority) {
1427+ console . warn (
1428+ 'The "priority" option passed to the useEvent() hook was different between renders.' +
1429+ ' The "priority" option is static and should never change between renders.' ,
1430+ ) ;
1431+ }
1432+ if (memoizedEvent.passive !== event.passive) {
1433+ console . warn (
1434+ 'The "passive" option passed to the useEvent() hook was different between renders.' +
1435+ ' The "passive" option is static and should never change between renders.' ,
1436+ ) ;
1437+ }
1438+ }
1439+ // In order to clear up upon the hook unmounting,
1440+ // we ensure we set the effecrt tag so that we visit
1441+ // this effect in the commit phase, so we can handle
1442+ // clean-up accordingly.
1443+ currentlyRenderingFiber . effectTag |= UpdateEffect ;
1444+ pushEffect ( NoHookEffect , noOpMount , clear , null ) ;
1445+ return reactListenerMap ;
1446+ }
1447+ // To make Flow not complain
1448+ return ( undefined : any ) ;
1449+ }
1450+
13721451export const ContextOnlyDispatcher : Dispatcher = {
13731452 readContext ,
13741453
@@ -1385,6 +1464,7 @@ export const ContextOnlyDispatcher: Dispatcher = {
13851464 useResponder : throwInvalidHookError ,
13861465 useDeferredValue : throwInvalidHookError ,
13871466 useTransition : throwInvalidHookError ,
1467+ useEvent : throwInvalidHookError ,
13881468} ;
13891469
13901470const HooksDispatcherOnMount: Dispatcher = {
@@ -1403,6 +1483,7 @@ const HooksDispatcherOnMount: Dispatcher = {
14031483 useResponder : createDeprecatedResponderListener ,
14041484 useDeferredValue : mountDeferredValue ,
14051485 useTransition : mountTransition ,
1486+ useEvent : mountEventListener ,
14061487} ;
14071488
14081489const HooksDispatcherOnUpdate: Dispatcher = {
@@ -1421,6 +1502,7 @@ const HooksDispatcherOnUpdate: Dispatcher = {
14211502 useResponder : createDeprecatedResponderListener ,
14221503 useDeferredValue : updateDeferredValue ,
14231504 useTransition : updateTransition ,
1505+ useEvent : updateEventListener ,
14241506} ;
14251507
14261508const HooksDispatcherOnRerender: Dispatcher = {
@@ -1439,6 +1521,7 @@ const HooksDispatcherOnRerender: Dispatcher = {
14391521 useResponder : createDeprecatedResponderListener ,
14401522 useDeferredValue : rerenderDeferredValue ,
14411523 useTransition : rerenderTransition ,
1524+ useEvent : updateEventListener ,
14421525} ;
14431526
14441527let HooksDispatcherOnMountInDEV: Dispatcher | null = null;
@@ -1588,6 +1671,11 @@ if (__DEV__) {
15881671 mountHookTypesDev ( ) ;
15891672 return mountTransition ( config ) ;
15901673 } ,
1674+ useEvent(event: ReactListenerEvent): ReactListenerMap {
1675+ currentHookNameInDev = 'useEvent' ;
1676+ mountHookTypesDev ( ) ;
1677+ return mountEventListener ( event ) ;
1678+ } ,
15911679 } ;
15921680
15931681 HooksDispatcherOnMountWithHookTypesInDEV = {
@@ -1705,6 +1793,11 @@ if (__DEV__) {
17051793 updateHookTypesDev ( ) ;
17061794 return mountTransition ( config ) ;
17071795 } ,
1796+ useEvent(event: ReactListenerEvent): ReactListenerMap {
1797+ currentHookNameInDev = 'useEvent' ;
1798+ updateHookTypesDev ( ) ;
1799+ return mountEventListener ( event ) ;
1800+ } ,
17081801 } ;
17091802
17101803 HooksDispatcherOnUpdateInDEV = {
@@ -1822,6 +1915,11 @@ if (__DEV__) {
18221915 updateHookTypesDev ( ) ;
18231916 return updateTransition ( config ) ;
18241917 } ,
1918+ useEvent(event: ReactListenerEvent): ReactListenerMap {
1919+ currentHookNameInDev = 'useEvent' ;
1920+ updateHookTypesDev ( ) ;
1921+ return updateEventListener ( event ) ;
1922+ } ,
18251923 } ;
18261924
18271925 HooksDispatcherOnRerenderInDEV = {
@@ -1939,6 +2037,11 @@ if (__DEV__) {
19392037 updateHookTypesDev ( ) ;
19402038 return rerenderTransition ( config ) ;
19412039 } ,
2040+ useEvent(event: ReactListenerEvent): ReactListenerMap {
2041+ currentHookNameInDev = 'useEvent' ;
2042+ updateHookTypesDev ( ) ;
2043+ return updateEventListener ( event ) ;
2044+ } ,
19422045 } ;
19432046
19442047 InvalidNestedHooksDispatcherOnMountInDEV = {
@@ -2070,6 +2173,12 @@ if (__DEV__) {
20702173 mountHookTypesDev ( ) ;
20712174 return mountTransition ( config ) ;
20722175 } ,
2176+ useEvent(event: ReactListenerEvent): ReactListenerMap {
2177+ currentHookNameInDev = 'useEvent' ;
2178+ warnInvalidHookAccess ( ) ;
2179+ mountHookTypesDev ( ) ;
2180+ return mountEventListener ( event ) ;
2181+ } ,
20732182 } ;
20742183
20752184 InvalidNestedHooksDispatcherOnUpdateInDEV = {
@@ -2201,6 +2310,12 @@ if (__DEV__) {
22012310 updateHookTypesDev ( ) ;
22022311 return updateTransition ( config ) ;
22032312 } ,
2313+ useEvent(event: ReactListenerEvent): ReactListenerMap {
2314+ currentHookNameInDev = 'useEvent' ;
2315+ warnInvalidHookAccess ( ) ;
2316+ updateHookTypesDev ( ) ;
2317+ return updateEventListener ( event ) ;
2318+ } ,
22042319 } ;
22052320
22062321 InvalidNestedHooksDispatcherOnRerenderInDEV = {
@@ -2332,5 +2447,11 @@ if (__DEV__) {
23322447 updateHookTypesDev ( ) ;
23332448 return rerenderTransition ( config ) ;
23342449 } ,
2450+ useEvent(event: ReactListenerEvent): ReactListenerMap {
2451+ currentHookNameInDev = 'useEvent' ;
2452+ warnInvalidHookAccess ( ) ;
2453+ updateHookTypesDev ( ) ;
2454+ return updateEventListener ( event ) ;
2455+ } ,
23352456 } ;
23362457}
0 commit comments