Ingro
Ingro

Reputation: 2841

Render React Components from PHP

I'm using ReactJS to power a simple filterable item list and it works quite well for my need.

The problem is that I need to render the markup on the server for SEO reasons, but when I call React.renderComponent() it replace the existing markup with the one generated by React.

Searching in React's docs I found this note:

React.renderComponent() replaces the contents of the container node you pass in. In the future, it may be possible to insert a component to an existing DOM node without overwriting the existing children.

Moreover I can't use React.renderComponentToString() to generate the markup server-side because my backend runs on PHP...

Is there any (even if hackish) way to achieve this with the current release (0.11.2)?

I suppose that if that's possible with markup generated by renderComponentToString() there should be a way to mock that result?

Thank you for any advice!

Upvotes: 5

Views: 13090

Answers (2)

Dimitar Dimitrov
Dimitar Dimitrov

Reputation: 119

You can look at https://github.com/reactjs/react-php-v8js

It renders react UI components on the server-side with PHP.

The implementation is very simple and the only requirement is that you need to be able to setup the V8Js PHP extension on your server.

Upvotes: 7

Brigand
Brigand

Reputation: 86250

The short answer is: not really.

The only sensible way to do it would be having a node process running which php can request renders from. This isn't a bad solution especially for pages that are heavily cached.

I suggest setting it up in a very dynamic way:

<?php 
function render_component_to_string($component, $data) 
{
  $url = "http://localhost:9000/components/" 
    . $component 
    . "?data=" 
    . rawurlencode(json_encode($data));
  return file_get_contents($url)
}
?>
<div id="myFilteredList">
  <?= render_component_to_string("FilteredList", 
        array("items" => items, "title" => "My List")) ?>
</div>

In node.js:

var app = require('express')(); // [email protected]
var React = require('react');

// create a dictionary of components 
// Object.create(null) because the key is supplied
var components = Object.create(null);
components.FilteredList = require('./components/filtered-list.js');

app.get('/component/:componentName', function(req, res){
  var component = components[req.params.componentName];

  // safety first!
  if (!component) {
    console.error("Invalid component", req.params.componentName);
    return res.send(404);
  }

  // more safety
  try {
    var data = JSON.parse(req.query.data);
  }
  catch (e) {
    console.error("Invalid JSON", req.params.componentName, req.query.data);
    return res.send(400);
  }

  // render and send the result back
  try {
    var result = React.renderComponentToString(component(data));
  }
  catch (e) {
    console.error('Could not render', req.params.componentName,
                  'with props', data);
    console.error(e.message, '\n', e.stack);
    return res.send(400);
  }
  res.send(result);
});


app.listen(9000);

This of course assumes your components are in commonjs modules. If they're not, this is another reason to do so!


I haven't used php in a few years, so please update this answer if I made any mistakes.

Upvotes: 0

Related Questions