Skip to content

Commit

Permalink
Remove enableAsyncActions
Browse files Browse the repository at this point in the history
  • Loading branch information
rickhanlonii committed Dec 13, 2024
1 parent 617e6d9 commit 2fe57eb
Show file tree
Hide file tree
Showing 24 changed files with 381 additions and 663 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2581,7 +2581,6 @@ describe('ReactHooksInspectionIntegration', () => {
`);
});

// @gate enableAsyncActions
it('should support useOptimistic hook', async () => {
const useOptimistic = React.useOptimistic;
function Foo() {
Expand Down Expand Up @@ -2647,7 +2646,6 @@ describe('ReactHooksInspectionIntegration', () => {
`);
});

// @gate enableAsyncActions
it('should support useActionState hook', async () => {
function Foo() {
const [value] = React.useActionState(function increment(n) {
Expand Down
6 changes: 2 additions & 4 deletions packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ import {
enableCreateEventHandleAPI,
enableScopeAPI,
enableTrustedTypesIntegration,
enableAsyncActions,
disableLegacyMode,
enableMoveBefore,
} from 'shared/ReactFeatureFlags';
Expand Down Expand Up @@ -1378,9 +1377,8 @@ function getNextHydratable(node: ?Node) {
nodeData === SUSPENSE_START_DATA ||
nodeData === SUSPENSE_FALLBACK_START_DATA ||
nodeData === SUSPENSE_PENDING_START_DATA ||
(enableAsyncActions &&
(nodeData === FORM_STATE_IS_MATCHING ||
nodeData === FORM_STATE_IS_NOT_MATCHING))
nodeData === FORM_STATE_IS_MATCHING ||
nodeData === FORM_STATE_IS_NOT_MATCHING
) {
break;
}
Expand Down
21 changes: 6 additions & 15 deletions packages/react-dom-bindings/src/shared/ReactDOMFormActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import type {Dispatcher} from 'react-reconciler/src/ReactInternalTypes';
import type {Awaited} from 'shared/ReactTypes';

import {enableAsyncActions} from 'shared/ReactFeatureFlags';
import ReactSharedInternals from 'shared/ReactSharedInternals';
import ReactDOMSharedInternals from 'shared/ReactDOMSharedInternals';

Expand Down Expand Up @@ -66,27 +65,19 @@ function resolveDispatcher() {
}

export function useFormStatus(): FormStatus {
if (!enableAsyncActions) {
throw new Error('Not implemented.');
} else {
const dispatcher = resolveDispatcher();
// $FlowFixMe[not-a-function] We know this exists because of the feature check above.
return dispatcher.useHostTransitionStatus();
}
const dispatcher = resolveDispatcher();
// $FlowFixMe[not-a-function] We know this exists because of the feature check above.
return dispatcher.useHostTransitionStatus();
}

export function useFormState<S, P>(
action: (Awaited<S>, P) => S,
initialState: Awaited<S>,
permalink?: string,
): [Awaited<S>, (P) => void, boolean] {
if (!enableAsyncActions) {
throw new Error('Not implemented.');
} else {
const dispatcher = resolveDispatcher();
// $FlowFixMe[not-a-function] This is unstable, thus optional
return dispatcher.useFormState(action, initialState, permalink);
}
const dispatcher = resolveDispatcher();
// $FlowFixMe[not-a-function] This is unstable, thus optional
return dispatcher.useFormState(action, initialState, permalink);
}

export function requestFormReset(form: HTMLFormElement) {
Expand Down
3 changes: 0 additions & 3 deletions packages/react-dom/src/__tests__/ReactDOMFizzForm-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,6 @@ describe('ReactDOMFizzForm', () => {
expect(buttonRef.current.hasAttribute('formTarget')).toBe(false);
});

// @gate enableAsyncActions
it('useFormStatus is not pending during server render', async () => {
function App() {
const {pending} = useFormStatus();
Expand Down Expand Up @@ -488,7 +487,6 @@ describe('ReactDOMFizzForm', () => {
expect(rootActionCalled).toBe(false);
});

// @gate enableAsyncActions
it('useOptimistic returns passthrough value', async () => {
function App() {
const [optimisticState] = useOptimistic('hi');
Expand All @@ -507,7 +505,6 @@ describe('ReactDOMFizzForm', () => {
expect(container.textContent).toBe('hi');
});

// @gate enableAsyncActions
it('useActionState returns initial state', async () => {
async function action(state) {
return state;
Expand Down
2 changes: 0 additions & 2 deletions packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6330,7 +6330,6 @@ describe('ReactDOMFizzServer', () => {
expect(getVisibleChildren(container)).toEqual('Hi');
});

// @gate enableAsyncActions
it('useActionState hydrates without a mismatch', async () => {
// This is testing an implementation detail: useActionState emits comment
// nodes into the SSR stream, so this checks that they are handled correctly
Expand Down Expand Up @@ -6383,7 +6382,6 @@ describe('ReactDOMFizzServer', () => {
expect(childRef.current).toBe(child);
});

// @gate enableAsyncActions
it("useActionState hydrates without a mismatch if there's a render phase update", async () => {
async function action(state) {
return state;
Expand Down
25 changes: 0 additions & 25 deletions packages/react-dom/src/__tests__/ReactDOMForm-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,6 @@ describe('ReactDOMForm', () => {
expect(actionCalled).toBe(false);
});

// @gate enableAsyncActions
it('form actions are transitions', async () => {
const formRef = React.createRef();

Expand Down Expand Up @@ -707,7 +706,6 @@ describe('ReactDOMForm', () => {
expect(container.textContent).toBe('Updated');
});

// @gate enableAsyncActions
it('multiple form actions', async () => {
const formRef = React.createRef();

Expand Down Expand Up @@ -798,12 +796,6 @@ describe('ReactDOMForm', () => {
});

it('sync errors in form actions can be captured by an error boundary', async () => {
if (gate(flags => !flags.enableAsyncActions)) {
// TODO: Uncaught JSDOM errors fail the test after the scope has finished
// so don't work with the `gate` mechanism.
return;
}

class ErrorBoundary extends React.Component {
state = {error: null};
static getDerivedStateFromError(error) {
Expand Down Expand Up @@ -844,12 +836,6 @@ describe('ReactDOMForm', () => {
});

it('async errors in form actions can be captured by an error boundary', async () => {
if (gate(flags => !flags.enableAsyncActions)) {
// TODO: Uncaught JSDOM errors fail the test after the scope has finished
// so don't work with the `gate` mechanism.
return;
}

class ErrorBoundary extends React.Component {
state = {error: null};
static getDerivedStateFromError(error) {
Expand Down Expand Up @@ -895,7 +881,6 @@ describe('ReactDOMForm', () => {
expect(container.textContent).toBe('Oh no!');
});

// @gate enableAsyncActions
it('useFormStatus reads the status of a pending form action', async () => {
const formRef = React.createRef();

Expand Down Expand Up @@ -992,7 +977,6 @@ describe('ReactDOMForm', () => {
);
});

// @gate enableAsyncActions
it('useActionState updates state asynchronously and queues multiple actions', async () => {
let actionCounter = 0;
async function action(state, type) {
Expand Down Expand Up @@ -1052,7 +1036,6 @@ describe('ReactDOMForm', () => {
expect(container.textContent).toBe('2');
});

// @gate enableAsyncActions
it('useActionState supports inline actions', async () => {
let increment;
function App({stepSize}) {
Expand Down Expand Up @@ -1084,7 +1067,6 @@ describe('ReactDOMForm', () => {
assertLog(['Pending 1', '11']);
});

// @gate enableAsyncActions
it('useActionState: dispatch throws if called during render', async () => {
function App() {
const [state, dispatch, isPending] = useActionState(async () => {}, 0);
Expand All @@ -1100,7 +1082,6 @@ describe('ReactDOMForm', () => {
});
});

// @gate enableAsyncActions
it('useActionState: queues multiple actions and runs them in order', async () => {
let action;
function App() {
Expand Down Expand Up @@ -1132,7 +1113,6 @@ describe('ReactDOMForm', () => {
expect(container.textContent).toBe('D');
});

// @gate enableAsyncActions
it(
'useActionState: when calling a queued action, uses the implementation ' +
'that was current at the time it was dispatched, not the most recent one',
Expand Down Expand Up @@ -1179,7 +1159,6 @@ describe('ReactDOMForm', () => {
},
);

// @gate enableAsyncActions
it('useActionState: works if action is sync', async () => {
let increment;
function App({stepSize}) {
Expand Down Expand Up @@ -1211,7 +1190,6 @@ describe('ReactDOMForm', () => {
assertLog(['Pending 1', '11']);
});

// @gate enableAsyncActions
it('useActionState: can mix sync and async actions', async () => {
let action;
function App() {
Expand Down Expand Up @@ -1239,7 +1217,6 @@ describe('ReactDOMForm', () => {
expect(container.textContent).toBe('E');
});

// @gate enableAsyncActions
it('useActionState: error handling (sync action)', async () => {
class ErrorBoundary extends React.Component {
state = {error: null};
Expand Down Expand Up @@ -1288,7 +1265,6 @@ describe('ReactDOMForm', () => {
expect(container.textContent).toBe('Caught an error: Oops!');
});

// @gate enableAsyncActions
it('useActionState: error handling (async action)', async () => {
class ErrorBoundary extends React.Component {
state = {error: null};
Expand Down Expand Up @@ -1394,7 +1370,6 @@ describe('ReactDOMForm', () => {
expect(container.textContent).toBe('Caught an error: Oops!');
});

// @gate enableAsyncActions
it('useActionState works in StrictMode', async () => {
let actionCounter = 0;
async function action(state, type) {
Expand Down
7 changes: 2 additions & 5 deletions packages/react-dom/src/client/ReactDOMRoot.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import type {
import {isValidContainer} from 'react-dom-bindings/src/client/ReactDOMContainer';
import {queueExplicitHydrationTarget} from 'react-dom-bindings/src/events/ReactDOMEventReplaying';
import {REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
import {enableAsyncActions} from 'shared/ReactFeatureFlags';

export type RootType = {
render(children: ReactNodeList): void,
Expand Down Expand Up @@ -305,10 +304,8 @@ export function hydrateRoot(
if (options.unstable_transitionCallbacks !== undefined) {
transitionCallbacks = options.unstable_transitionCallbacks;
}
if (enableAsyncActions) {
if (options.formState !== undefined) {
formState = options.formState;
}
if (options.formState !== undefined) {
formState = options.formState;
}
}

Expand Down
95 changes: 46 additions & 49 deletions packages/react-reconciler/src/ReactFiberBeginWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ import {
enableTransitionTracing,
enableLegacyHidden,
enableCPUSuspense,
enableAsyncActions,
enablePostpone,
enableRenderableContext,
disableLegacyMode,
Expand Down Expand Up @@ -1619,55 +1618,53 @@ function updateHostComponent(
workInProgress.flags |= ContentReset;
}

if (enableAsyncActions) {
const memoizedState = workInProgress.memoizedState;
if (memoizedState !== null) {
// This fiber has been upgraded to a stateful component. The only way
// happens currently is for form actions. We use hooks to track the
// pending and error state of the form.
//
// Once a fiber is upgraded to be stateful, it remains stateful for the
// rest of its lifetime.
const newState = renderTransitionAwareHostComponentWithHooks(
current,
workInProgress,
renderLanes,
);
const memoizedState = workInProgress.memoizedState;
if (memoizedState !== null) {
// This fiber has been upgraded to a stateful component. The only way
// happens currently is for form actions. We use hooks to track the
// pending and error state of the form.
//
// Once a fiber is upgraded to be stateful, it remains stateful for the
// rest of its lifetime.
const newState = renderTransitionAwareHostComponentWithHooks(
current,
workInProgress,
renderLanes,
);

// If the transition state changed, propagate the change to all the
// descendents. We use Context as an implementation detail for this.
//
// This is intentionally set here instead of pushHostContext because
// pushHostContext gets called before we process the state hook, to avoid
// a state mismatch in the event that something suspends.
//
// NOTE: This assumes that there cannot be nested transition providers,
// because the only renderer that implements this feature is React DOM,
// and forms cannot be nested. If we did support nested providers, then
// we would need to push a context value even for host fibers that
// haven't been upgraded yet.
if (isPrimaryRenderer) {
HostTransitionContext._currentValue = newState;
} else {
HostTransitionContext._currentValue2 = newState;
}
if (enableLazyContextPropagation) {
// In the lazy propagation implementation, we don't scan for matching
// consumers until something bails out.
} else {
if (didReceiveUpdate) {
if (current !== null) {
const oldStateHook: Hook = current.memoizedState;
const oldState: TransitionStatus = oldStateHook.memoizedState;
// This uses regular equality instead of Object.is because we assume
// that host transition state doesn't include NaN as a valid type.
if (oldState !== newState) {
propagateContextChange(
workInProgress,
HostTransitionContext,
renderLanes,
);
}
// If the transition state changed, propagate the change to all the
// descendents. We use Context as an implementation detail for this.
//
// This is intentionally set here instead of pushHostContext because
// pushHostContext gets called before we process the state hook, to avoid
// a state mismatch in the event that something suspends.
//
// NOTE: This assumes that there cannot be nested transition providers,
// because the only renderer that implements this feature is React DOM,
// and forms cannot be nested. If we did support nested providers, then
// we would need to push a context value even for host fibers that
// haven't been upgraded yet.
if (isPrimaryRenderer) {
HostTransitionContext._currentValue = newState;
} else {
HostTransitionContext._currentValue2 = newState;
}
if (enableLazyContextPropagation) {
// In the lazy propagation implementation, we don't scan for matching
// consumers until something bails out.
} else {
if (didReceiveUpdate) {
if (current !== null) {
const oldStateHook: Hook = current.memoizedState;
const oldState: TransitionStatus = oldStateHook.memoizedState;
// This uses regular equality instead of Object.is because we assume
// that host transition state doesn't include NaN as a valid type.
if (oldState !== newState) {
propagateContextChange(
workInProgress,
HostTransitionContext,
renderLanes,
);
}
}
}
Expand Down
Loading

0 comments on commit 2fe57eb

Please sign in to comment.