Skip to content

Commit 5aa5554

Browse files
committed
RFC, useServerContextsForRefetch
1 parent d74b7bd commit 5aa5554

File tree

7 files changed

+150
-6
lines changed

7 files changed

+150
-6
lines changed

packages/react-client/src/ReactFlightClient.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
} from './ReactFlightClientHostConfig';
2626

2727
import {getOrCreateServerContext} from './ReactServerContext';
28+
import {ServerContextWrapper} from './ReactFlightClientContext';
2829

2930
import {
3031
REACT_LAZY_TYPE,
@@ -345,11 +346,10 @@ export function parseModelTuple(
345346
// Or even change the ReactElement type to be an array.
346347
return createElement(tuple[1], tuple[2], tuple[3]);
347348
case REACT_PROVIDER_TYPE:
348-
return createElement(
349-
getOrCreateServerContext((tuple[1]: any)).Provider,
350-
tuple[2],
351-
tuple[3],
352-
);
349+
return createElement(ServerContextWrapper, tuple[2], {
350+
...tuple[3],
351+
ServerContext: getOrCreateServerContext((tuple[1]: any)),
352+
});
353353
}
354354
return value;
355355
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import * as React from 'react';
2+
3+
const {useContext, useMemo, createContext} = React;
4+
5+
const ServerContextContext = createContext(null);
6+
7+
type ServerContextNodeType = {
8+
parent: null | ServerContextNodeType,
9+
name: string,
10+
value: any,
11+
};
12+
13+
export function ServerContextWrapper({ServerContext, value, children}) {
14+
const parent = useContext(ServerContextContext);
15+
const context = useMemo(() => {
16+
const ctx = {
17+
parent: parent,
18+
name: ServerContext.displayName,
19+
value: value,
20+
};
21+
if (__DEV__) {
22+
return Object.freeze(ctx);
23+
}
24+
return ctx;
25+
}, [parent, value]);
26+
return (
27+
<ServerContextContext.Provider value={context}>
28+
<ServerContext.Provider value={value}>{children}</ServerContext.Provider>
29+
</ServerContextContext.Provider>
30+
);
31+
}
32+
33+
export function useServerContextsForRefetch() {
34+
return useContext(ServerContextContext);
35+
}

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 =
@@ -651,5 +654,88 @@ describe('ReactFlight', () => {
651654
</>,
652655
);
653656
});
657+
658+
// @gate enableServerContext
659+
it('supports useServerContextsForRefetch', () => {
660+
const ServerContext = React.createServerContext(
661+
'ServerContext',
662+
'default',
663+
);
664+
665+
function Foo() {
666+
return (
667+
<>
668+
<ServerContext.Provider value="hi this is server outer">
669+
<ServerContext.Provider value="hi this is server">
670+
<Bar value="" />
671+
</ServerContext.Provider>
672+
<ServerContext.Provider value="hi this is server2">
673+
<Bar value="2" />
674+
</ServerContext.Provider>
675+
<Bar value="outer" />
676+
</ServerContext.Provider>
677+
<ServerContext.Provider value="hi this is server outer2">
678+
<Bar value="outer2" />
679+
</ServerContext.Provider>
680+
<Bar value="default" />
681+
</>
682+
);
683+
}
684+
const contextsForRefetch = [];
685+
function ClientBaz() {
686+
const context = React.useContext(ServerContext);
687+
contextsForRefetch.push(
688+
ReactNoopFlightHooks.useServerContextsForRefetch(),
689+
);
690+
return <span>{context}</span>;
691+
}
692+
function ClientBar({value}) {
693+
return (
694+
<ServerContext.Provider
695+
value={'hi this is client' + (value ? ' ' + value : '')}>
696+
<ClientBaz />
697+
</ServerContext.Provider>
698+
);
699+
}
700+
const Bar = moduleReference(ClientBar);
701+
702+
const transport = ReactNoopFlightServer.render(<Foo />);
703+
act(() => {
704+
ServerContext._currentRenderer = null;
705+
ServerContext._currentRenderer2 = null;
706+
ReactNoop.render(ReactNoopFlightClient.read(transport));
707+
});
708+
expect(ReactNoop).toMatchRenderedOutput(
709+
<>
710+
<span>hi this is client</span>
711+
<span>hi this is client 2</span>
712+
<span>hi this is client outer</span>
713+
<span>hi this is client outer2</span>
714+
<span>hi this is client default</span>
715+
</>,
716+
);
717+
const outer = {
718+
parent: null,
719+
name: 'ServerContext',
720+
value: 'hi this is server outer',
721+
};
722+
expect(contextsForRefetch[0]).toEqual({
723+
parent: outer,
724+
name: 'ServerContext',
725+
value: 'hi this is server',
726+
});
727+
expect(contextsForRefetch[1]).toEqual({
728+
parent: outer,
729+
name: 'ServerContext',
730+
value: 'hi this is server2',
731+
});
732+
expect(contextsForRefetch[2]).toEqual(outer);
733+
expect(contextsForRefetch[3]).toEqual({
734+
parent: null,
735+
name: 'ServerContext',
736+
value: 'hi this is server outer2',
737+
});
738+
expect(contextsForRefetch[4]).toEqual(null);
739+
});
654740
});
655741
});
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/ReactFlightClientContext';

packages/react-noop-renderer/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"flight-client.js",
2929
"flight-modules.js",
3030
"flight-server.js",
31+
"flight-hooks.js",
3132
"cjs/"
3233
]
3334
}
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/ReactFlightClientContext';

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

Lines changed: 3 additions & 1 deletion
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": {

0 commit comments

Comments
 (0)