Skip to content

[WIP] Add useEvent #24505

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions packages/react-reconciler/src/ReactFiberHooks.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ import {
requestEventTime,
markSkippedUpdateLanes,
isInterleavedUpdate,
isAlreadyRenderingProd,
} from './ReactFiberWorkLoop.new';

import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
Expand Down Expand Up @@ -1730,6 +1731,47 @@ function updateEffect(
return updateEffectImpl(PassiveEffect, HookPassive, create, deps);
}

function mountEvent<T>(callback: T): T {
const hook = mountWorkInProgressHook();
const ref = {current: callback};

function event(...args) {
if (isAlreadyRenderingProd()) {
throw new Error('An event from useEvent was called during render.');
}
return ref.current.apply(this, args);
}

mountEffectImpl(
UpdateEffect,
HookInsertion,
() => {
ref.current = callback;
},
[ref, callback],
);

hook.memoizedState = [ref, event];

return event;
}

function updateEvent<T>(callback: T): T {
const hook = updateWorkInProgressHook();
const ref = hook.memoizedState[0];

updateEffectImpl(
UpdateEffect,
HookInsertion,
() => {
ref.current = callback;
},
[ref, callback],
);

return hook.memoizedState[1];
}

function mountInsertionEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
Expand Down Expand Up @@ -2430,6 +2472,7 @@ export const ContextOnlyDispatcher: Dispatcher = {
useCallback: throwInvalidHookError,
useContext: throwInvalidHookError,
useEffect: throwInvalidHookError,
useEvent: throwInvalidHookError,
useImperativeHandle: throwInvalidHookError,
useInsertionEffect: throwInvalidHookError,
useLayoutEffect: throwInvalidHookError,
Expand Down Expand Up @@ -2458,6 +2501,7 @@ const HooksDispatcherOnMount: Dispatcher = {
useCallback: mountCallback,
useContext: readContext,
useEffect: mountEffect,
useEvent: mountEvent,
useImperativeHandle: mountImperativeHandle,
useLayoutEffect: mountLayoutEffect,
useInsertionEffect: mountInsertionEffect,
Expand Down Expand Up @@ -2485,6 +2529,7 @@ const HooksDispatcherOnUpdate: Dispatcher = {
useCallback: updateCallback,
useContext: readContext,
useEffect: updateEffect,
useEvent: updateEvent,
useImperativeHandle: updateImperativeHandle,
useInsertionEffect: updateInsertionEffect,
useLayoutEffect: updateLayoutEffect,
Expand Down Expand Up @@ -2513,6 +2558,7 @@ const HooksDispatcherOnRerender: Dispatcher = {
useCallback: updateCallback,
useContext: readContext,
useEffect: updateEffect,
useEvent: updateEvent,
useImperativeHandle: updateImperativeHandle,
useInsertionEffect: updateInsertionEffect,
useLayoutEffect: updateLayoutEffect,
Expand Down Expand Up @@ -2586,6 +2632,11 @@ if (__DEV__) {
checkDepsAreArrayDev(deps);
return mountEffect(create, deps);
},
useEvent<T>(callback: T): T {
currentHookNameInDev = 'useEvent';
mountHookTypesDev();
return mountEvent(callback);
},
useImperativeHandle<T>(
ref: {|current: T | null|} | ((inst: T | null) => mixed) | null | void,
create: () => T,
Expand Down Expand Up @@ -2732,6 +2783,11 @@ if (__DEV__) {
updateHookTypesDev();
return mountEffect(create, deps);
},
useEvent<T>(callback: T): T {
currentHookNameInDev = 'useEvent';
updateHookTypesDev();
return mountEvent(callback);
},
useImperativeHandle<T>(
ref: {|current: T | null|} | ((inst: T | null) => mixed) | null | void,
create: () => T,
Expand Down Expand Up @@ -2874,6 +2930,11 @@ if (__DEV__) {
updateHookTypesDev();
return updateEffect(create, deps);
},
useEvent<T>(callback: T): T {
currentHookNameInDev = 'useEvent';
updateHookTypesDev();
return updateEvent(callback);
},
useImperativeHandle<T>(
ref: {|current: T | null|} | ((inst: T | null) => mixed) | null | void,
create: () => T,
Expand Down Expand Up @@ -3017,6 +3078,11 @@ if (__DEV__) {
updateHookTypesDev();
return updateEffect(create, deps);
},
useEvent<T>(callback: T): T {
currentHookNameInDev = 'useEvent';
updateHookTypesDev();
return updateEvent(callback);
},
useImperativeHandle<T>(
ref: {|current: T | null|} | ((inst: T | null) => mixed) | null | void,
create: () => T,
Expand Down Expand Up @@ -3163,6 +3229,12 @@ if (__DEV__) {
mountHookTypesDev();
return mountEffect(create, deps);
},
useEvent<T>(callback: T): T {
currentHookNameInDev = 'useEvent';
warnInvalidHookAccess();
mountHookTypesDev();
return mountEvent(callback);
},
useImperativeHandle<T>(
ref: {|current: T | null|} | ((inst: T | null) => mixed) | null | void,
create: () => T,
Expand Down Expand Up @@ -3322,6 +3394,12 @@ if (__DEV__) {
updateHookTypesDev();
return updateEffect(create, deps);
},
useEvent<T>(callback: T): T {
currentHookNameInDev = 'useEvent';
warnInvalidHookAccess();
updateHookTypesDev();
return updateEvent(callback);
},
useImperativeHandle<T>(
ref: {|current: T | null|} | ((inst: T | null) => mixed) | null | void,
create: () => T,
Expand Down Expand Up @@ -3482,6 +3560,12 @@ if (__DEV__) {
updateHookTypesDev();
return updateEffect(create, deps);
},
useEvent<T>(callback: T): T {
currentHookNameInDev = 'useEvent';
warnInvalidHookAccess();
updateHookTypesDev();
return updateEvent(callback);
},
useImperativeHandle<T>(
ref: {|current: T | null|} | ((inst: T | null) => mixed) | null | void,
create: () => T,
Expand Down
84 changes: 84 additions & 0 deletions packages/react-reconciler/src/ReactFiberHooks.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ import {
requestEventTime,
markSkippedUpdateLanes,
isInterleavedUpdate,
isAlreadyRenderingProd,
} from './ReactFiberWorkLoop.old';

import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
Expand Down Expand Up @@ -1730,6 +1731,47 @@ function updateEffect(
return updateEffectImpl(PassiveEffect, HookPassive, create, deps);
}

function mountEvent<T>(callback: T): T {
const hook = mountWorkInProgressHook();
const ref = {current: callback};

function event(...args) {
if (isAlreadyRenderingProd()) {
throw new Error('An event from useEvent was called during render.');
}
return ref.current.apply(this, args);
}

mountEffectImpl(
UpdateEffect,
HookInsertion,
() => {
ref.current = callback;
},
[ref, callback],
);

hook.memoizedState = [ref, event];

return event;
}

function updateEvent<T>(callback: T): T {
const hook = updateWorkInProgressHook();
const ref = hook.memoizedState[0];

updateEffectImpl(
UpdateEffect,
HookInsertion,
() => {
ref.current = callback;
},
[ref, callback],
);

return hook.memoizedState[1];
}

function mountInsertionEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
Expand Down Expand Up @@ -2430,6 +2472,7 @@ export const ContextOnlyDispatcher: Dispatcher = {
useCallback: throwInvalidHookError,
useContext: throwInvalidHookError,
useEffect: throwInvalidHookError,
useEvent: throwInvalidHookError,
useImperativeHandle: throwInvalidHookError,
useInsertionEffect: throwInvalidHookError,
useLayoutEffect: throwInvalidHookError,
Expand Down Expand Up @@ -2458,6 +2501,7 @@ const HooksDispatcherOnMount: Dispatcher = {
useCallback: mountCallback,
useContext: readContext,
useEffect: mountEffect,
useEvent: mountEvent,
useImperativeHandle: mountImperativeHandle,
useLayoutEffect: mountLayoutEffect,
useInsertionEffect: mountInsertionEffect,
Expand Down Expand Up @@ -2485,6 +2529,7 @@ const HooksDispatcherOnUpdate: Dispatcher = {
useCallback: updateCallback,
useContext: readContext,
useEffect: updateEffect,
useEvent: updateEvent,
useImperativeHandle: updateImperativeHandle,
useInsertionEffect: updateInsertionEffect,
useLayoutEffect: updateLayoutEffect,
Expand Down Expand Up @@ -2513,6 +2558,7 @@ const HooksDispatcherOnRerender: Dispatcher = {
useCallback: updateCallback,
useContext: readContext,
useEffect: updateEffect,
useEvent: updateEvent,
useImperativeHandle: updateImperativeHandle,
useInsertionEffect: updateInsertionEffect,
useLayoutEffect: updateLayoutEffect,
Expand Down Expand Up @@ -2586,6 +2632,11 @@ if (__DEV__) {
checkDepsAreArrayDev(deps);
return mountEffect(create, deps);
},
useEvent<T>(callback: T): T {
currentHookNameInDev = 'useEvent';
mountHookTypesDev();
return mountEvent(callback);
},
useImperativeHandle<T>(
ref: {|current: T | null|} | ((inst: T | null) => mixed) | null | void,
create: () => T,
Expand Down Expand Up @@ -2732,6 +2783,11 @@ if (__DEV__) {
updateHookTypesDev();
return mountEffect(create, deps);
},
useEvent<T>(callback: T): T {
currentHookNameInDev = 'useEvent';
updateHookTypesDev();
return mountEvent(callback);
},
useImperativeHandle<T>(
ref: {|current: T | null|} | ((inst: T | null) => mixed) | null | void,
create: () => T,
Expand Down Expand Up @@ -2874,6 +2930,11 @@ if (__DEV__) {
updateHookTypesDev();
return updateEffect(create, deps);
},
useEvent<T>(callback: T): T {
currentHookNameInDev = 'useEvent';
updateHookTypesDev();
return updateEvent(callback);
},
useImperativeHandle<T>(
ref: {|current: T | null|} | ((inst: T | null) => mixed) | null | void,
create: () => T,
Expand Down Expand Up @@ -3017,6 +3078,11 @@ if (__DEV__) {
updateHookTypesDev();
return updateEffect(create, deps);
},
useEvent<T>(callback: T): T {
currentHookNameInDev = 'useEvent';
updateHookTypesDev();
return updateEvent(callback);
},
useImperativeHandle<T>(
ref: {|current: T | null|} | ((inst: T | null) => mixed) | null | void,
create: () => T,
Expand Down Expand Up @@ -3163,6 +3229,12 @@ if (__DEV__) {
mountHookTypesDev();
return mountEffect(create, deps);
},
useEvent<T>(callback: T): T {
currentHookNameInDev = 'useEvent';
warnInvalidHookAccess();
mountHookTypesDev();
return mountEvent(callback);
},
useImperativeHandle<T>(
ref: {|current: T | null|} | ((inst: T | null) => mixed) | null | void,
create: () => T,
Expand Down Expand Up @@ -3322,6 +3394,12 @@ if (__DEV__) {
updateHookTypesDev();
return updateEffect(create, deps);
},
useEvent<T>(callback: T): T {
currentHookNameInDev = 'useEvent';
warnInvalidHookAccess();
updateHookTypesDev();
return updateEvent(callback);
},
useImperativeHandle<T>(
ref: {|current: T | null|} | ((inst: T | null) => mixed) | null | void,
create: () => T,
Expand Down Expand Up @@ -3482,6 +3560,12 @@ if (__DEV__) {
updateHookTypesDev();
return updateEffect(create, deps);
},
useEvent<T>(callback: T): T {
currentHookNameInDev = 'useEvent';
warnInvalidHookAccess();
updateHookTypesDev();
return updateEvent(callback);
},
useImperativeHandle<T>(
ref: {|current: T | null|} | ((inst: T | null) => mixed) | null | void,
create: () => T,
Expand Down
9 changes: 9 additions & 0 deletions packages/react-reconciler/src/ReactFiberWorkLoop.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -1354,6 +1354,10 @@ export function getExecutionContext(): ExecutionContext {
return executionContext;
}

export function isCurrentlyRendering(): boolean {
return (executionContext & (RenderContext | CommitContext)) !== NoContext;
}

export function deferredUpdates<A>(fn: () => A): A {
const previousPriority = getCurrentUpdatePriority();
const prevTransition = ReactCurrentBatchConfig.transition;
Expand Down Expand Up @@ -1464,6 +1468,11 @@ export function isAlreadyRendering() {
);
}

export function isAlreadyRenderingProd() {
// Used to throw if certain APIs are called from the wrong context.
return (executionContext & RenderContext) !== NoContext;
}

export function flushControlled(fn: () => mixed): void {
const prevExecutionContext = executionContext;
executionContext |= BatchedContext;
Expand Down
9 changes: 9 additions & 0 deletions packages/react-reconciler/src/ReactFiberWorkLoop.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -1354,6 +1354,10 @@ export function getExecutionContext(): ExecutionContext {
return executionContext;
}

export function isCurrentlyRendering(): boolean {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused fn ?

return (executionContext & (RenderContext | CommitContext)) !== NoContext;
}

export function deferredUpdates<A>(fn: () => A): A {
const previousPriority = getCurrentUpdatePriority();
const prevTransition = ReactCurrentBatchConfig.transition;
Expand Down Expand Up @@ -1464,6 +1468,11 @@ export function isAlreadyRendering() {
);
}

export function isAlreadyRenderingProd() {
// Used to throw if certain APIs are called from the wrong context.
return (executionContext & RenderContext) !== NoContext;
}

export function flushControlled(fn: () => mixed): void {
const prevExecutionContext = executionContext;
executionContext |= BatchedContext;
Expand Down
Loading