---
title: renderToReadableStream
---
`renderToReadableStream`는 [Readable Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)을 이용해 React 트리를 그립니다.
```js
const stream = await renderToReadableStream(reactNode, options?)
```
이 API는 [Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API)에 의존합니다. Node.js의 경우, [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream)을 대신 사용하세요.
---
## 레퍼런스 {/*reference*/}
### `renderToReadableStream(reactNode, options?)` {/*rendertoreadablestream*/}
`renderToReadableStream`을 호출하여 React 트리를 HTML로 [Readable Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)에 렌더링합니다.
```js
import { renderToReadableStream } from 'react-dom/server';
async function handler(request) {
const stream = await renderToReadableStream(, {
bootstrapScripts: ['/main.js']
});
return new Response(stream, {
headers: { 'content-type': 'text/html' },
});
}
```
클라이언트에서, [`hydrateRoot`](/reference/react-dom/client/hydrateRoot)를 호출해 서버에서 생성된 HTML을 상호작용 가능하도록 만듭니다.
[아래에서 더 많은 예시를 확인하세요.](#usage)
#### 매개변수 {/*parameters*/}
* `reactNode`: 사용자가 HTML로 렌더링하고 하고자하는 React node입니다. ``같은 JSX 요소가 그 예시입니다. reactNode 인자는 문서 전체를 표현할 수 있는 것이어야하며, 따라서 `App` 컴포넌트는 ``에 렌더링됩니다.
* **optional** `options`: 스트리밍 옵션을 지정할 수 있는 객체입니다.
* **optional** `bootstrapScriptContent`: 지정될 경우, 해당 문자열은 `
```
클라이언트에선, 추가된 bootstrap 스크립트는 [`hydrateRoot`를 호출해 `document` 전체를 hydrate 해야합니다](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document).
```js [[1, 4, ""]]
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';
hydrateRoot(document, );
```
이 과정은 서버에서 렌더링된 HTML에 이벤트 리스너들을 붙이고, HTML을 상호작용 가능하게 만듭니다.
#### 빌드 결과물에서 CSS와 JS의 경로 읽어오기 {/*reading-css-and-js-asset-paths-from-the-build-output*/}
JS와 CSS같은 최종 에셋들에 대한 URL들은 종종 빌드 후에 해시됩니다. 예를 들어, `styles.css` 대신 `styles.123456.css`와 같은 형태로 끝날 수 있습니다. 에셋들의 파일명을 해시하는 것은 모든 빌드의 결과물이 각각 다른 파일명을 가지도록 보장합니다. 이는 정적 에셋들에 대한 장기 캐싱을 안전하게 활성화할 수 있도록 해줍니다. 즉, 특정 이름의 파일 내용은 절대 바뀌지 않는 다는 것을 보장합니다.
하지만, 빌드 후에 에셋들의 URL을 알 수 없다면, 소스 코드에 URL을 넣을 수 없습니다. 예를 들어, JSX에 `"/styles.css"`를 하드코딩하는 것은 작동하지 않습니다. 소스 코드에 URL을 넣지 않으려면, 루트 컴포넌트는 props로 전달된 맵에서 실제 파일명을 읽어야합니다.
```js {1,6}
export default function App({ assetMap }) {
return (
My app
...
);
}
```
서버에선 ``을 렌더링하고, 에셋 URL들과 함께 `assetMap`을 전달합니다.
```js {1-5,8,9}
// 빌드 도구로부터 이 JSON을 얻어야합니다. 예를 들어, 빌드 결과물에서 읽어올 수 있습니다.
const assetMap = {
'styles.css': '/styles.123456.css',
'main.js': '/main.123456.js'
};
async function handler(request) {
const stream = await renderToReadableStream(, {
bootstrapScripts: [assetMap['/main.js']]
});
return new Response(stream, {
headers: { 'content-type': 'text/html' },
});
}
```
서버가 ``를 렌더링한 이후엔, 클라이언트에서도 hydration 오류를 피하기 위해 `assetMap`과 함께 렌더링해야합니다. `assetMap`을 직렬화하고 클라이언트에 전달하기 위해 다음과 같이 할 수 있습니다.
```js {9-10}
// 빌드 도구로부터 이 JSON을 얻어야합니다.
const assetMap = {
'styles.css': '/styles.123456.css',
'main.js': '/main.123456.js'
};
async function handler(request) {
const stream = await renderToReadableStream(, {
// 주의: 이 데이터는 사용자가 생성하지 않았기 때문에 stringify()를 사용해도 안전합니다.
bootstrapScriptContent: `window.assetMap = ${JSON.stringify(assetMap)};`,
bootstrapScripts: [assetMap['/main.js']],
});
return new Response(stream, {
headers: { 'content-type': 'text/html' },
});
}
```
위의 예시에서, `bootstrapScriptContent` 옵션은 클라이언트에서 `window.assetMap` 전역 변수를 설정하는 인라인 `