ps_md
ps_md

Reputation: 209

ReactDOM Hydrate Renders HTML as Text on Client Page

I am trying to do a simple test and I know I am missing something simple.

I have two applications, one hosted on node (localhost:3000) and another is hosted on another site (http://development.azure). The section site is not running under node, its standard IIS.

In my node server application i have the following

import { renderToString } from "react-dom/server"

app.get("/", (req, res) => {
    const name = 'Marvelous Peter'
    res.write("<!DOCTYPE html><html><head><title>My Page</title></head><body>");
    res.write("<div id='content'>");
    res.write(renderToString(<Hello name={name} />));
    res.write("</div></body></html>");
    res.end();
});

app.listen(3000)

In my IIS application I am attempting to load the react component using xhr and then hydrate it.

const xhr = require("xhr");

        xhr({
            method: "GET",
            uri: "http://localhost:3000",

        }, (err, resp, body) => {
            // check resp.statusCode
            ReactDOM.hydrate(body, document.getElementById("test"),  () => {

            });
        });

I am seeing the output on my page, however, it is not HTML encoded. I renders as text

<!DOCTYPE html><html><head><title>My Page</title></head><body><div id='content'><div data-reactroot=""><h1>Hello, <!-- -->Marvelous Peter<!-- -->!</h1></div></div></body></html>

I tried returning only the renderToString value and not HTML and still get the same thing, specifically since i have tags in the component

import React from 'react'

const Hello = (props) => (
    <div><h1>Hello, {props.name}!</h1></div>
)

export default Hello

I know I am missing something, but I am finding it hard to find info on doing this and would appreciate any help!

Thanks in advance!

EDIT:

Per the suggestion below, I tried to create a simple component and then hydrate it but I still get the same response.

Here is the new component:

import * as React from "react";
import * as ReactDOM from "react-dom";

class Hello extends React.Component {
    public load() {
        const xhr = require("xhr");
        let res = null;
        xhr({
            method: "get",
            sync: true,
            uri: "http://localhost:3000"
        }, (err, resp, body) => {
            res = body;
        });
        return res;
    }
    public render(): JSX.Element {
        const val = this.load()
        return val;
    }
}

const target: any = document.querySelector("#main");
if (target) {
    ReactDOM.hydrate(<Hello />, target);
}

I am rather stumped right now. Could it have to do with the response header type from the xhr request?

Any suggestions?

Upvotes: 1

Views: 2196

Answers (3)

I still don't have enough reputation to comment on your main question, but have you tried setting the response content-type in express as 'text/html'?

import { renderToString } from "react-dom/server"

app.get("/", (req, res) => {
    const name = 'Marvelous Peter'
    res.setHeader('content-type', 'text/html'); // add this line
    res.write("<!DOCTYPE html><html><head><title>My Page</title></head><body>");
    res.write("<div id='content'>");
    res.write(renderToString(<Hello name={name} />));
    res.write("</div></body></html>");
    res.end();
});

app.listen(3000)

Usually browsers will only understand that they need to render the incoming data as html if this header is specified.

Upvotes: 0

Shanon Jackson
Shanon Jackson

Reputation: 6571

JSX !== HTML they may appear the same but they are fundamentally different and cannot be used interchangeably.

<div/> in JSX is React.createElement("div");

<div></div> in HTML is document.createElement("div");

You cannot use HTML (or a HTML string) in place of a function in React that expects JSX (mainly ReactDOM.hydrate, ReactDOM.render, React.createElement("div", null, NEED JSX HERE).

In order to render it not as a string you'll have to use the only API implementation that React provides to turn a HTML string into something resembling JSX which is...

dangerouslySetInnerHTML={{__html: YOUR STRING HERE}}

try this..

ReactDOM.render(<div dangerouslySetInnerHTML={{__html: YOURSTRINGHERE}}/>, document.body)

Upvotes: 3

Train
Train

Reputation: 3496

It's expects an Element, not a string.

ReactDOM.hydrate(
  <MyComponent />,
  document.getElementById('root')
)

Take that HTML response and create a react component out of it. Then pass it in your .hydrate method.

Upvotes: 0

Related Questions