Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fe7163e

Browse files
authored
Add unstable prefix to experimental APIs (facebook#18825)
We've been shipping unprefixed experimental APIs (like `createRoot` and `useTransition`) to the Experimental release channel, with the rationale that because these APIs do not appear in any stable release, we're free to change or remove them later without breaking any downstream projects. What we didn't consider is that downstream projects might be tempted to use feature detection: ```js const useTransition = React.useTransition || fallbackUseTransition; ``` This pattern assumes that the version of `useTransition` that exists in the Experimental channel today has the same API contract as the final `useTransition` API that we'll eventually ship to stable. To discourage feature detection, I've added an `unstable_` prefix to all of our unstable APIs. The Facebook builds still have the unprefixed APIs, though. We will continue to support those; if we make any breaking changes, we'll migrate the internal callers like we usually do. To make testing easier, I added the `unstable_`-prefixed APIs to the www builds, too. That way our tests can always use the prefixed ones without gating on the release channel.
1 parent cd4a960 commit fe7163e

31 files changed

+280
-214
lines changed

fixtures/blocks/src/server/App.block.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
/* eslint-disable import/first */
88

99
import * as React from 'react';
10-
import {block} from 'react';
10+
import {unstable_block as block} from 'react';
1111

1212
// Server
1313

fixtures/dom/src/__tests__/wrong-act-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ it("doesn't warn if you use nested acts from different renderers", () => {
179179

180180
if (__EXPERIMENTAL__) {
181181
it('warns when using createRoot() + .render', () => {
182-
const root = ReactDOM.createRoot(document.createElement('div'));
182+
const root = ReactDOM.unstable_createRoot(document.createElement('div'));
183183
expect(() => {
184184
TestRenderer.act(() => {
185185
root.render(<App />);

packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js

Lines changed: 103 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -366,121 +366,123 @@ describe('ReactHooksInspectionIntegration', () => {
366366
]);
367367
});
368368

369-
if (__EXPERIMENTAL__) {
370-
it('should support composite useTransition hook', () => {
371-
function Foo(props) {
372-
React.useTransition();
373-
const memoizedValue = React.useMemo(() => 'hello', []);
374-
return <div>{memoizedValue}</div>;
375-
}
376-
const renderer = ReactTestRenderer.create(<Foo />);
377-
const childFiber = renderer.root.findByType(Foo)._currentFiber();
378-
const tree = ReactDebugTools.inspectHooksOfFiber(childFiber);
379-
expect(tree).toEqual([
380-
{
381-
id: 0,
382-
isStateEditable: false,
383-
name: 'Transition',
384-
value: undefined,
385-
subHooks: [],
386-
},
387-
{
388-
id: 1,
389-
isStateEditable: false,
390-
name: 'Memo',
391-
value: 'hello',
392-
subHooks: [],
393-
},
394-
]);
395-
});
396-
397-
it('should support composite useDeferredValue hook', () => {
398-
function Foo(props) {
399-
React.useDeferredValue('abc', {
400-
timeoutMs: 500,
401-
});
402-
const [state] = React.useState(() => 'hello', []);
403-
return <div>{state}</div>;
404-
}
405-
const renderer = ReactTestRenderer.create(<Foo />);
406-
const childFiber = renderer.root.findByType(Foo)._currentFiber();
407-
const tree = ReactDebugTools.inspectHooksOfFiber(childFiber);
408-
expect(tree).toEqual([
409-
{
410-
id: 0,
411-
isStateEditable: false,
412-
name: 'DeferredValue',
413-
value: 'abc',
414-
subHooks: [],
415-
},
416-
{
417-
id: 1,
418-
isStateEditable: true,
419-
name: 'State',
420-
value: 'hello',
421-
subHooks: [],
422-
},
423-
]);
424-
});
425-
426-
it('should support composite useOpaqueIdentifier hook', () => {
427-
function Foo(props) {
428-
const id = React.unstable_useOpaqueIdentifier();
429-
const [state] = React.useState(() => 'hello', []);
430-
return <div id={id}>{state}</div>;
431-
}
432-
433-
const renderer = ReactTestRenderer.create(<Foo />);
434-
const childFiber = renderer.root.findByType(Foo)._currentFiber();
435-
const tree = ReactDebugTools.inspectHooksOfFiber(childFiber);
436-
437-
expect(tree.length).toEqual(2);
438-
439-
expect(tree[0].id).toEqual(0);
440-
expect(tree[0].isStateEditable).toEqual(false);
441-
expect(tree[0].name).toEqual('OpaqueIdentifier');
442-
expect((tree[0].value + '').startsWith('c_')).toBe(true);
369+
// @gate experimental
370+
it('should support composite useTransition hook', () => {
371+
function Foo(props) {
372+
React.unstable_useTransition();
373+
const memoizedValue = React.useMemo(() => 'hello', []);
374+
return <div>{memoizedValue}</div>;
375+
}
376+
const renderer = ReactTestRenderer.create(<Foo />);
377+
const childFiber = renderer.root.findByType(Foo)._currentFiber();
378+
const tree = ReactDebugTools.inspectHooksOfFiber(childFiber);
379+
expect(tree).toEqual([
380+
{
381+
id: 0,
382+
isStateEditable: false,
383+
name: 'Transition',
384+
value: undefined,
385+
subHooks: [],
386+
},
387+
{
388+
id: 1,
389+
isStateEditable: false,
390+
name: 'Memo',
391+
value: 'hello',
392+
subHooks: [],
393+
},
394+
]);
395+
});
443396

444-
expect(tree[1]).toEqual({
397+
// @gate experimental
398+
it('should support composite useDeferredValue hook', () => {
399+
function Foo(props) {
400+
React.unstable_useDeferredValue('abc', {
401+
timeoutMs: 500,
402+
});
403+
const [state] = React.useState(() => 'hello', []);
404+
return <div>{state}</div>;
405+
}
406+
const renderer = ReactTestRenderer.create(<Foo />);
407+
const childFiber = renderer.root.findByType(Foo)._currentFiber();
408+
const tree = ReactDebugTools.inspectHooksOfFiber(childFiber);
409+
expect(tree).toEqual([
410+
{
411+
id: 0,
412+
isStateEditable: false,
413+
name: 'DeferredValue',
414+
value: 'abc',
415+
subHooks: [],
416+
},
417+
{
445418
id: 1,
446419
isStateEditable: true,
447420
name: 'State',
448421
value: 'hello',
449422
subHooks: [],
450-
});
423+
},
424+
]);
425+
});
426+
427+
// @gate experimental
428+
it('should support composite useOpaqueIdentifier hook', () => {
429+
function Foo(props) {
430+
const id = React.unstable_useOpaqueIdentifier();
431+
const [state] = React.useState(() => 'hello', []);
432+
return <div id={id}>{state}</div>;
433+
}
434+
435+
const renderer = ReactTestRenderer.create(<Foo />);
436+
const childFiber = renderer.root.findByType(Foo)._currentFiber();
437+
const tree = ReactDebugTools.inspectHooksOfFiber(childFiber);
438+
439+
expect(tree.length).toEqual(2);
440+
441+
expect(tree[0].id).toEqual(0);
442+
expect(tree[0].isStateEditable).toEqual(false);
443+
expect(tree[0].name).toEqual('OpaqueIdentifier');
444+
expect((tree[0].value + '').startsWith('c_')).toBe(true);
445+
446+
expect(tree[1]).toEqual({
447+
id: 1,
448+
isStateEditable: true,
449+
name: 'State',
450+
value: 'hello',
451+
subHooks: [],
451452
});
453+
});
452454

453-
it('should support composite useOpaqueIdentifier hook in concurrent mode', () => {
454-
function Foo(props) {
455-
const id = React.unstable_useOpaqueIdentifier();
456-
const [state] = React.useState(() => 'hello', []);
457-
return <div id={id}>{state}</div>;
458-
}
455+
// @gate experimental
456+
it('should support composite useOpaqueIdentifier hook in concurrent mode', () => {
457+
function Foo(props) {
458+
const id = React.unstable_useOpaqueIdentifier();
459+
const [state] = React.useState(() => 'hello', []);
460+
return <div id={id}>{state}</div>;
461+
}
459462

460-
const renderer = ReactTestRenderer.create(<Foo />, {
461-
unstable_isConcurrent: true,
462-
});
463-
expect(Scheduler).toFlushWithoutYielding();
463+
const renderer = ReactTestRenderer.create(<Foo />, {
464+
unstable_isConcurrent: true,
465+
});
466+
expect(Scheduler).toFlushWithoutYielding();
464467

465-
const childFiber = renderer.root.findByType(Foo)._currentFiber();
466-
const tree = ReactDebugTools.inspectHooksOfFiber(childFiber);
468+
const childFiber = renderer.root.findByType(Foo)._currentFiber();
469+
const tree = ReactDebugTools.inspectHooksOfFiber(childFiber);
467470

468-
expect(tree.length).toEqual(2);
471+
expect(tree.length).toEqual(2);
469472

470-
expect(tree[0].id).toEqual(0);
471-
expect(tree[0].isStateEditable).toEqual(false);
472-
expect(tree[0].name).toEqual('OpaqueIdentifier');
473-
expect((tree[0].value + '').startsWith('c_')).toBe(true);
473+
expect(tree[0].id).toEqual(0);
474+
expect(tree[0].isStateEditable).toEqual(false);
475+
expect(tree[0].name).toEqual('OpaqueIdentifier');
476+
expect((tree[0].value + '').startsWith('c_')).toBe(true);
474477

475-
expect(tree[1]).toEqual({
476-
id: 1,
477-
isStateEditable: true,
478-
name: 'State',
479-
value: 'hello',
480-
subHooks: [],
481-
});
478+
expect(tree[1]).toEqual({
479+
id: 1,
480+
isStateEditable: true,
481+
name: 'State',
482+
value: 'hello',
483+
subHooks: [],
482484
});
483-
}
485+
});
484486

485487
describe('useDebugValue', () => {
486488
it('should support inspectable values for multiple custom hooks', () => {

packages/react-devtools-shared/src/__tests__/store-test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,18 +352,18 @@ describe('Store', () => {
352352
};
353353
const Wrapper = ({shouldSuspense}) => (
354354
<React.Fragment>
355-
<React.SuspenseList revealOrder="forwards" tail="collapsed">
355+
<React.unstable_SuspenseList revealOrder="forwards" tail="collapsed">
356356
<Component key="A" />
357357
<React.Suspense fallback={<Loading />}>
358358
{shouldSuspense ? <SuspendingComponent /> : <Component key="B" />}
359359
</React.Suspense>
360360
<Component key="C" />
361-
</React.SuspenseList>
361+
</React.unstable_SuspenseList>
362362
</React.Fragment>
363363
);
364364

365365
const container = document.createElement('div');
366-
const root = ReactDOM.createRoot(container);
366+
const root = ReactDOM.unstable_createRoot(container);
367367
act(() => {
368368
root.render(<Wrapper shouldSuspense={true} />);
369369
});

0 commit comments

Comments
 (0)