Skip to content

Commit

Permalink
Merge branch 'main' into component-stack-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
KarimP authored Sep 25, 2023
2 parents 364938d + 94d5b5b commit 08883b3
Show file tree
Hide file tree
Showing 237 changed files with 12,467 additions and 6,687 deletions.
6 changes: 2 additions & 4 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -415,9 +415,7 @@ module.exports = {
},
},
{
files: [
'packages/react-native-renderer/**/*.js',
],
files: ['packages/react-native-renderer/**/*.js'],
globals: {
nativeFabricUIManager: 'readonly',
},
Expand Down Expand Up @@ -456,6 +454,7 @@ module.exports = {
$ReadOnlyArray: 'readonly',
$ArrayBufferView: 'readonly',
$Shape: 'readonly',
ReturnType: 'readonly',
AnimationFrameID: 'readonly',
// For Flow type annotation. Only `BigInt` is valid at runtime.
bigint: 'readonly',
Expand Down Expand Up @@ -492,7 +491,6 @@ module.exports = {
ReadableStreamController: 'readonly',
RequestInfo: 'readonly',
RequestOptions: 'readonly',
ResponseState: 'readonly',
StoreAsGlobal: 'readonly',
symbol: 'readonly',
SyntheticEvent: 'readonly',
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ React is a JavaScript library for building user interfaces.
* **Component-Based:** Build encapsulated components that manage their own state, then compose them to make complex UIs. Since component logic is written in JavaScript instead of templates, you can easily pass rich data through your app and keep the state out of the DOM.
* **Learn Once, Write Anywhere:** We don't make assumptions about the rest of your technology stack, so you can develop new features in React without rewriting existing code. React can also render on the server using Node and power mobile apps using [React Native](https://reactnative.dev/).

[Learn how to use React in your project](https://reactjs.org/docs/getting-started.html).
[Learn how to use React in your project](https://react.dev/learn).

## Installation

Expand All @@ -20,9 +20,9 @@ You can use React as a `<script>` tag from a [CDN](https://reactjs.org/docs/cdn-

## Documentation

You can find the React documentation [on the website](https://reactjs.org/).
You can find the React documentation [on the website](https://react.dev/).

Check out the [Getting Started](https://reactjs.org/docs/getting-started.html) page for a quick overview.
Check out the [Getting Started](https://react.dev/learn) page for a quick overview.

The documentation is divided into several sections:

Expand Down
6 changes: 5 additions & 1 deletion fixtures/flight/server/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,15 @@ app.all('/', async function (req, res, next) {
// For HTML, we're a "client" emulator that runs the client code,
// so we start by consuming the RSC payload. This needs a module
// map that reverse engineers the client-side path to the SSR path.
const root = await createFromNodeStream(rscResponse, moduleMap);
const {root, formState} = await createFromNodeStream(
rscResponse,
moduleMap
);
// Render it into HTML by resolving the client components
res.set('Content-type', 'text/html');
const {pipe} = renderToPipeableStream(root, {
bootstrapScripts: mainJSChunks,
experimental_formState: formState,
});
pipe(res);
} catch (e) {
Expand Down
15 changes: 9 additions & 6 deletions fixtures/flight/server/region.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const {readFile} = require('fs').promises;

const React = require('react');

async function renderApp(res, returnValue) {
async function renderApp(res, returnValue, formState) {
const {renderToPipeableStream} = await import(
'react-server-dom-webpack/server'
);
Expand Down Expand Up @@ -93,13 +93,13 @@ async function renderApp(res, returnValue) {
React.createElement(App),
];
// For client-invoked server actions we refresh the tree and return a return value.
const payload = returnValue ? {returnValue, root} : root;
const payload = {root, returnValue, formState};
const {pipe} = renderToPipeableStream(payload, moduleMap);
pipe(res);
}

app.get('/', async function (req, res) {
await renderApp(res, null);
await renderApp(res, null, null);
});

app.post('/', bodyParser.text(), async function (req, res) {
Expand All @@ -108,6 +108,7 @@ app.post('/', bodyParser.text(), async function (req, res) {
decodeReply,
decodeReplyFromBusboy,
decodeAction,
decodeFormState,
} = await import('react-server-dom-webpack/server');
const serverReference = req.get('rsc-action');
if (serverReference) {
Expand Down Expand Up @@ -139,7 +140,7 @@ app.post('/', bodyParser.text(), async function (req, res) {
// We handle the error on the client
}
// Refresh the client and return the value
renderApp(res, result);
renderApp(res, result, null);
} else {
// This is the progressive enhancement case
const UndiciRequest = require('undici').Request;
Expand All @@ -153,12 +154,14 @@ app.post('/', bodyParser.text(), async function (req, res) {
const action = await decodeAction(formData);
try {
// Wait for any mutations
await action();
const result = await action();
const formState = decodeFormState(result, formData);
renderApp(res, null, formState);
} catch (x) {
const {setServerState} = await import('../src/ServerState.js');
setServerState('Error: ' + x.message);
renderApp(res, null, null);
}
renderApp(res, null);
}
});

Expand Down
17 changes: 13 additions & 4 deletions fixtures/flight/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ const Counter3 = await(AsyncModule);
import ShowMore from './ShowMore.js';
import Button from './Button.js';
import Form from './Form.js';
import {Dynamic} from './Dynamic.js';
import {Client} from './Client.js';

import {like, greet} from './actions.js';
import {Note} from './cjs/Note.js';

import {like, greet, increment} from './actions.js';

import {getServerState} from './ServerState.js';

Expand All @@ -28,9 +32,9 @@ export default async function App() {
<body>
<Container>
<h1>{getServerState()}</h1>
<Counter />
<Counter2 />
<Counter3 />
<Counter incrementAction={increment} />
<Counter2 incrementAction={increment} />
<Counter3 incrementAction={increment} />
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.text}</li>
Expand All @@ -43,6 +47,11 @@ export default async function App() {
<div>
<Button action={like}>Like</Button>
</div>
<div>
loaded statically: <Dynamic />
</div>
<Client />
<Note />
</Container>
</body>
</html>
Expand Down
21 changes: 21 additions & 0 deletions fixtures/flight/src/Client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use client';

import * as React from 'react';

let LazyDynamic = React.lazy(() =>
import('./Dynamic.js').then(exp => ({default: exp.Dynamic}))
);

export function Client() {
const [loaded, load] = React.useReducer(() => true, false);

return loaded ? (
<div>
loaded dynamically: <LazyDynamic />
</div>
) : (
<div>
<button onClick={load}>Load dynamic import Component</button>
</div>
);
}
9 changes: 6 additions & 3 deletions fixtures/flight/src/Counter.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
'use client';

import * as React from 'react';
import {experimental_useFormState as useFormState} from 'react-dom';

import Container from './Container.js';

export function Counter() {
const [count, setCount] = React.useState(0);
export function Counter({incrementAction}) {
const [count, incrementFormAction] = useFormState(incrementAction, 0);
return (
<Container>
<button onClick={() => setCount(c => c + 1)}>Count: {count}</button>
<form>
<button formAction={incrementFormAction}>Count: {count}</button>
</form>
</Container>
);
}
12 changes: 12 additions & 0 deletions fixtures/flight/src/Dynamic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use client';

import * as React from 'react';

export function Dynamic() {
return (
<div>
This client component should be loaded in a single chunk even when it is
used as both a client reference and as a dynamic import.
</div>
);
}
4 changes: 4 additions & 0 deletions fixtures/flight/src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ export async function greet(formData) {
}
return 'Hi ' + name + '!';
}

export async function increment(n) {
return n + 1;
}
11 changes: 11 additions & 0 deletions fixtures/flight/src/cjs/Note.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'use client';

var React = require('react');

function Note() {
return 'This component was exported on a commonJS module and imported into ESM as a named import.';
}

module.exports = {
Note,
};
38 changes: 25 additions & 13 deletions fixtures/flight/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,33 @@ async function callServer(id, args) {
return returnValue;
}

let data = createFromFetch(
fetch('/', {
headers: {
Accept: 'text/x-component',
},
}),
{
callServer,
}
);

function Shell({data}) {
const [root, setRoot] = useState(use(data));
const [root, setRoot] = useState(data);
updateRoot = setRoot;
return root;
}

ReactDOM.hydrateRoot(document, <Shell data={data} />);
async function hydrateApp() {
const {root, returnValue, formState} = await createFromFetch(
fetch('/', {
headers: {
Accept: 'text/x-component',
},
}),
{
callServer,
}
);

ReactDOM.hydrateRoot(document, <Shell data={root} />, {
// TODO: This part doesn't actually work because the server only returns
// form state during the request that submitted the form. Which means it
// the state needs to be transported as part of the HTML stream. We intend
// to add a feature to Fizz for this, but for now it's up to the
// metaframework to implement correctly.
experimental_formState: formState,
});
}

// Remove this line to simulate MPA behavior
hydrateApp();
Loading

0 comments on commit 08883b3

Please sign in to comment.