RSCを使った時のrenderingの流れ
APIが呼ばれた時に、rootであるserver componentがserver上でrenderingする
server componentは、renderingしちゃってdivやpなどのHTML要素にする
client componentは、代わりにplaceholder ("$"とか)を使った形式にする
bundle時に、モジュール参照オブジェクトを作る ref POSTDでは、type.filenameにclient componentのpathを入れる、と書いてるが、今は少し別の実装になっている
filepath + nameではなく$$idを見るようになった
clientで、上記の要素を1つずつ受け取る
HTML要素ならそのままrenderingすれば良い
placeholderにぶち当たったらsuspendする
placeholderの中身が来たらそこに代入する
client componentの場合は、通常通りclientでrenderingしてDOMにcommitする
参考
code:packages/react-server/src/ReactFlightServer.js(ts)
function resolveModelToJSON(
request: Request,
parent:
| $ReadOnlyArray<ReactClientValue>,
key: string,
value: ReactClientValue,
): ReactJSONValue {
// Make sure that
...
ReactModelを受け取って、
code:flow(ts)
export type ReactClientValue =
// Server Elements and Lazy Components are unwrapped on the Server
| React$Element<React$AbstractComponent<any, any>>
| LazyComponent<ReactClientValue, any>
// References are passed by their value
| ClientReference<any>
| ServerReference<any>
// The rest are passed as is. Sub-types can be passed in but lose their
// subtype, so the receiver can only accept once of these.
| React$Element<string>
| React$Element<ClientReference<any> & any>
| ReactServerContext<any>
| string
| boolean
| number
| symbol
| null
| void
| bigint
| Iterable<ReactClientValue>
| Array<ReactClientValue>
| Map<ReactClientValue, ReactClientValue>
| Set<ReactClientValue>
| Date
| ReactClientObject
| Promise<ReactClientValue>; // Thenable<ReactClientValue>
ReactJsonValueを返却
code:flow(ts)
type ReactJSONValue =
| string
| boolean
| number
| null
| $ReadOnlyArray<ReactJSONValue>
| ReactModelObject;
この部分でserver componentを変換している try節の中で、attemptResolveElement()を呼んで、server componentをrenderingしてHTMLに変換している
このattemptResolveElement()が内部でpromiseをthrowするとcatch節に入る
そのcactch節の中で、serializeLazyID()を呼んでる
これが'$L'を返すやつ
そのすぐ下でclient componentをserializeしてる serializeClientReference()を呼んでる
code:js
function serializeClientReference(
request: Request,
parent:
| $ReadOnlyArray<ReactClientValue>,
key: string,
clientReference: ClientReference<any>,
): string {
...
if (existingId !== undefined) {
if (parent0 === REACT_ELEMENT_TYPE && key === '1') { return serializeLazyID(existingId); // これとか
}
return serializeByValueID(existingId); // これが、
}
...
}
function serializeByValueID(id: number): string { // こんな感じで
return '$' + id.toString(16);
}
function serializeLazyID(id: number): string { // serializeしてる
return '$L' + id.toString(16);
}
registerClientReferenceImpl ref ClientReferenceを作っている
code:packages/react-server-dom-webpack/src/ReactFlightWebpackReferences.js
function registerClientReferenceImpl<T>(
proxyImplementation: any,
id: string,
async: boolean,
): ClientReference<T> {
return Object.defineProperties(proxyImplementation, {
$$typeof: {value: CLIENT_REFERENCE_TAG},
$$id: {value: id},
$$async: {value: async},
});
}