Skip to content

Commit 73065cc

Browse files
committed
reset
1 parent d5f1b06 commit 73065cc

File tree

11 files changed

+214
-6
lines changed

11 files changed

+214
-6
lines changed

packages/react-client/flight-hooks.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
*/
9+
10+
export {useServerContextsForRefetch} from './src/ReactFlightClient';
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
'use strict';
2+
3+
if (process.env.NODE_ENV === 'production') {
4+
module.exports = require('./cjs/react-client-flight-hooks.production.min.js');
5+
} else {
6+
module.exports = require('./cjs/react-client-flight-hooks.development.js');
7+
}

packages/react-client/package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,14 @@
1313
"LICENSE",
1414
"README.md",
1515
"flight.js",
16+
"flight-hooks.js",
1617
"cjs/"
1718
],
19+
"exports": {
20+
".": "./flight.js",
21+
"./flight": "./flight.js",
22+
"./flight-hooks": "./flight-hooks.js"
23+
},
1824
"repository": {
1925
"type" : "git",
2026
"url" : "https://github.com/facebook/react.git",

packages/react-client/src/ReactFlightClient.js

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,34 @@
77
* @flow
88
*/
99

10-
import type {Wakeable} from 'shared/ReactTypes';
10+
import type {Wakeable, ReactProviderType} from 'shared/ReactTypes';
1111
import type {LazyComponent} from 'react/src/ReactLazy';
12+
import type {
13+
ReactServerContext,
14+
ServerContextJSONValue,
15+
} from 'shared/ReactTypes';
1216

1317
import type {
1418
ModuleReference,
1519
ModuleMetaData,
1620
UninitializedModel,
1721
Response,
1822
} from './ReactFlightClientHostConfig';
19-
2023
import {
2124
resolveModuleReference,
2225
preloadModule,
2326
requireModule,
2427
parseModel,
2528
} from './ReactFlightClientHostConfig';
2629

27-
import {REACT_LAZY_TYPE, REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
28-
2930
import {getOrCreateServerContext} from 'shared/ReactServerContextRegistry';
31+
import {
32+
REACT_LAZY_TYPE,
33+
REACT_ELEMENT_TYPE,
34+
REACT_PROVIDER_TYPE,
35+
} from 'shared/ReactSymbols';
36+
37+
import {useContext, useMemo, createContext} from 'react';
3038

3139
export type JSONValue =
3240
| number
@@ -331,6 +339,12 @@ export function parseModelTuple(
331339
const tuple: [mixed, mixed, mixed, mixed] = (value: any);
332340

333341
if (tuple[0] === REACT_ELEMENT_TYPE) {
342+
if ((tuple[1]: any).$$typeof === REACT_PROVIDER_TYPE) {
343+
return createElement(ServerContextWrapper, null, {
344+
ServerContext: ((tuple[1]: any): ReactProviderType<any>)._context,
345+
...tuple[3],
346+
});
347+
}
334348
// TODO: Consider having React just directly accept these arrays as elements.
335349
// Or even change the ReactElement type to be an array.
336350
return createElement(tuple[1], tuple[2], tuple[3]);
@@ -434,3 +448,42 @@ export function close(response: Response): void {
434448
// ref count of pending chunks.
435449
reportGlobalError(response, new Error('Connection closed.'));
436450
}
451+
452+
const ServerContextContext = createContext(null);
453+
454+
type ServerContextNodeType = {
455+
parent: null | ServerContextNodeType,
456+
name: string,
457+
value: any,
458+
};
459+
460+
type Props = {
461+
ServerContext: ReactServerContext<any>,
462+
value: ServerContextJSONValue,
463+
children: any,
464+
};
465+
466+
function ServerContextWrapper({ServerContext, value, children}: Props) {
467+
const parent = useContext(ServerContextContext);
468+
469+
const context = useMemo(() => {
470+
const ctx = {
471+
parent: parent,
472+
name: ServerContext._globalName,
473+
value: value,
474+
};
475+
if (__DEV__) {
476+
return Object.freeze(ctx);
477+
}
478+
return ctx;
479+
}, [parent, value]);
480+
481+
return createElement(ServerContextContext.Provider, null, {
482+
value: context,
483+
children: createElement(ServerContext.Provider, null, {value, children}),
484+
});
485+
}
486+
487+
export function useServerContextsForRefetch() {
488+
return useContext(ServerContextContext);
489+
}

packages/react-client/src/__tests__/ReactFlight-test.js

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ let React;
1515
let ReactNoop;
1616
let ReactNoopFlightServer;
1717
let ReactNoopFlightClient;
18+
let ReactNoopFlightHooks;
1819
let ErrorBoundary;
1920
let NoErrorExpected;
2021
let Scheduler;
@@ -28,6 +29,8 @@ describe('ReactFlight', () => {
2829
ReactNoop = require('react-noop-renderer');
2930
ReactNoopFlightServer = require('react-noop-renderer/flight-server');
3031
ReactNoopFlightClient = require('react-noop-renderer/flight-client');
32+
ReactNoopFlightHooks = require('react-noop-renderer/flight-hooks');
33+
3134
act = require('jest-react').act;
3235
Scheduler = require('scheduler');
3336
const ReactSharedInternals =
@@ -653,5 +656,88 @@ describe('ReactFlight', () => {
653656
</>,
654657
);
655658
});
659+
660+
// @gate enableServerContext
661+
it('supports useServerContextsForRefetch', () => {
662+
const ServerContext = React.createServerContext(
663+
'ServerContext',
664+
'default',
665+
);
666+
667+
function Foo() {
668+
return (
669+
<>
670+
<ServerContext.Provider value="hi this is server outer">
671+
<ServerContext.Provider value="hi this is server">
672+
<Bar value="" />
673+
</ServerContext.Provider>
674+
<ServerContext.Provider value="hi this is server2">
675+
<Bar value="2" />
676+
</ServerContext.Provider>
677+
<Bar value="outer" />
678+
</ServerContext.Provider>
679+
<ServerContext.Provider value="hi this is server outer2">
680+
<Bar value="outer2" />
681+
</ServerContext.Provider>
682+
<Bar value="default" />
683+
</>
684+
);
685+
}
686+
const contextsForRefetch = [];
687+
function ClientBaz() {
688+
const context = React.useContext(ServerContext);
689+
contextsForRefetch.push(
690+
ReactNoopFlightHooks.useServerContextsForRefetch(),
691+
);
692+
return <span>{context}</span>;
693+
}
694+
function ClientBar({value}) {
695+
return (
696+
<ServerContext.Provider
697+
value={'hi this is client' + (value ? ' ' + value : '')}>
698+
<ClientBaz />
699+
</ServerContext.Provider>
700+
);
701+
}
702+
const Bar = moduleReference(ClientBar);
703+
704+
const transport = ReactNoopFlightServer.render(<Foo />);
705+
act(() => {
706+
ServerContext._currentRenderer = null;
707+
ServerContext._currentRenderer2 = null;
708+
ReactNoop.render(ReactNoopFlightClient.read(transport));
709+
});
710+
expect(ReactNoop).toMatchRenderedOutput(
711+
<>
712+
<span>hi this is client</span>
713+
<span>hi this is client 2</span>
714+
<span>hi this is client outer</span>
715+
<span>hi this is client outer2</span>
716+
<span>hi this is client default</span>
717+
</>,
718+
);
719+
const outer = {
720+
parent: null,
721+
name: 'ServerContext',
722+
value: 'hi this is server outer',
723+
};
724+
expect(contextsForRefetch[0]).toEqual({
725+
parent: outer,
726+
name: 'ServerContext',
727+
value: 'hi this is server',
728+
});
729+
expect(contextsForRefetch[1]).toEqual({
730+
parent: outer,
731+
name: 'ServerContext',
732+
value: 'hi this is server2',
733+
});
734+
expect(contextsForRefetch[2]).toEqual(outer);
735+
expect(contextsForRefetch[3]).toEqual({
736+
parent: null,
737+
name: 'ServerContext',
738+
value: 'hi this is server outer2',
739+
});
740+
expect(contextsForRefetch[4]).toEqual(null);
741+
});
656742
});
657743
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
*/
9+
10+
export {useServerContextsForRefetch} from 'react-client/flight-hooks';
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
'use strict';
2+
3+
if (process.env.NODE_ENV === 'production') {
4+
module.exports = require('./cjs/react-noop-renderer-flight-hooks.production.min.js');
5+
} else {
6+
module.exports = require('./cjs/react-noop-renderer-flight-hooks.development.js');
7+
}

packages/react-noop-renderer/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"flight-client.js",
2828
"flight-modules.js",
2929
"flight-server.js",
30+
"flight-hooks.js",
3031
"cjs/"
3132
]
3233
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
*/
9+
10+
export {useServerContextsForRefetch} from 'react-client/src/ReactFlightClient';

packages/react-server-dom-webpack/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"writer.browser.server.js",
1818
"writer.node.server.js",
1919
"node-register.js",
20+
"flight-hooks.js",
2021
"cjs/",
2122
"umd/",
2223
"esm/"
@@ -35,7 +36,8 @@
3536
"./writer.browser.server": "./writer.browser.server.js",
3637
"./node-loader": "./esm/react-server-dom-webpack-node-loader.js",
3738
"./node-register": "./node-register.js",
38-
"./package.json": "./package.json"
39+
"./package.json": "./package.json",
40+
"./flight-hooks": "./flight-hooks.js"
3941
},
4042
"main": "index.js",
4143
"repository": {
@@ -60,4 +62,4 @@
6062
"loose-envify"
6163
]
6264
}
63-
}
65+
}

0 commit comments

Comments
 (0)