I'm trying to accomplish server side rendering with React components in Express and templating with Jade. However I'm running into some issues.
Here is my server code, the entry point.
var app = require('express')();
var http = require('http').Server(app);
var React = require('react');
var ReactDOMServer = require('react-dom/server');
//Component
var Index = require('./views/components/index.jsx').default;
app.set('port', process.env.PORT || 3000);
app.set('views', `${__dirname}/views`);
app.set('view engine', 'jade');
app.get('/', (req, res) => {
var reactHTML = ReactDOMServer.renderToString(<Index/>);
res.render('test', { reactHTML: reactHTML });
});
http.listen(3000, () => {
console.log(`listening on port ${app.get('port')}`);
});
Here is my Index
component, it's actually just rendering a div with my ChatTextBox
component, which is this:
import React, { Component } from 'React';
class ChatTextBox extends Component {
constructor(props) {
super(props);
this.state = { term: 'test' };
this.termChange = this.termChange.bind(this);
this.handleClick = this.handleClick.bind(this);
}
handleClick(event) {
console.log('this was clicked');
this.setState({ term: '' });
}
termChange(event) {
console.log(event.target.value);
this.setState({ term: event.target.value });
}
render() {
return (
<div>
<input type="text"
value={this.state.term}
onChange={this.termChange} />
<button onClick={this.handleClick}>Send Message</button>
<div>{this.state.term}</div>
</div>
);
}
}
export default ChatTextBox;
edit:
Here is my jade template, test.jade
html
body
div#container
#{reactHTML}
Problems:
1) It's not rendering properly. Here is the result:
It's rendering the component twice, along with the '<', '>' symbols..?
2) None of the hooks work, in terms binding state and rendering dynamically. This makes sense though, I'm rendering static HTML in jade. So how would I accomplish this dynamically? (I think this is a bit off topic, I can make a separate concern for this).
Thank you for reading, hopefully this post was clear enough.
It looks like you're using Jade potentially redundantly. The usual approach with reactDOM server-side is to send the result of renderToString()
down to the client. If you do need to keep using Jade for whatever reason, you can tell it to unescape HTML strings with !=
. So, you can change your template to:
html
body
div#container
#{!=reactHTML}
That should ensure it's not double-rendering everything