markfinger / python-react

Server-side rendering of React components
MIT License
1.62k stars 116 forks source link

Is it possible to use Server Side Rendering for components that you want to pass children to? #71

Closed Anima-t3d closed 7 years ago

Anima-t3d commented 7 years ago

As I understand from the docs you can only pass the absolute url of a jsx file and pass props. Would it also be possible to pass child components to the server side renderer? Or would a somewhat workaround be to create another jsx file that has these child components in it and pass props?

markfinger commented 7 years ago

You could implement something like that with React components if you use the render method to handle the instantiation of - and branching between - the child components, but it'll probably involve jumping through a number of hoops and seems a bit hacky.

An alternative might be to re-implement the render server's js file with your own. If you're interested, it's pretty succinct and should be easy to hack on

markfinger commented 7 years ago

I've linked this question from the README. https://github.com/markfinger/python-react/blob/master/README.md#how-do-i-pass-child-components-to-the-root-component

Everyone should feel free to continue the discussion, if so inclined.

ryapapap commented 7 years ago

I was able to get this to work, but would be open to any suggestions if someone knows a better way. I modified the render server's js file from:

app.post('/render', function(req, res) {
    reactRender(req.body, function(err, markup) {

to

app.post('/render', function(req, res) {
        var component = require(req.body.path);
    reactRender({
             props: { children: component.default(JSON.parse(req.body.serializedProps)) },
             toStaticMarkup: false,
             path: '<path_to_my_main>',
  }, function(err, markup) {

I came up with this after looking at the code inside react-render, which is a bit more defensive (I'm not using any of the custom config options, so ymmv with this sample).

markfinger commented 7 years ago

@ryapapap that seems pretty reasonable.

The primary benefits of react-render is require caching (reduce IO) and some compatibility for different React versions. There's no massive benefit to using it, other than excising some boilerplate from the render server's script.

If you want more granular control of the render process, but still use the req/res conventions + handling in python-react, you could always just remove the reactRender call and replace it with your own React.renderToString call. You'll probably want to replicate some of the React Factory stuff (I think it's a one-liner and should be easy to find in react-render's code or React's docs) as I think that avoids re-running some of React's init code. Once you've got a reference to the component factory, it should be trivial to pass in any child components you like.

Either way, @ryapapap's code above should work well enough for most purposes.

ryapapap commented 7 years ago

That makes a lot of sense, thanks for the info!