16

I am trying to copy this fiddle: http://jsfiddle.net/jhudson8/135oo6f8/

(I also tried this example http://codepen.io/adamaoc/pen/wBGGQv and the same onClick handler problem exists)

and make the fiddle work for server side rendering, using ReactDOMServer.renderToString

I have this call:

   res.send(ReactDOMServer.renderToString((
            <html>
            <head>

                <link href={'/styles/style-accordion.css'} rel={'stylesheet'} type={'text/css'}></link>

            </head>

            <body>


            <Accordion selected='2'>
                <AccordionSection title='Section 1' id='1'>
                    Section 1 content
                </AccordionSection>
                <AccordionSection title='Section 2' id='2'>
                    Section 2 content
                </AccordionSection>
                <AccordionSection title='Section 3' id='3'>
                    Section 3 content
                </AccordionSection>
            </Accordion>
            </body>
            </html>
        )));

the Accordion element looks like so:

const React = require('react');

const fs = require('fs');
const path = require('path');


const Accordion = React.createClass({

    getInitialState: function () {
        // we should also listen for property changes and reset the state
        // but we aren't for this demo
        return {
            // initialize state with the selected section if provided
            selected: this.props.selected
        };
    },

    render: function () {

        // enhance the section contents so we can track clicks and show sections
        const children = React.Children.map(this.props.children, this.enhanceSection);

        return (
            <div className='accordion'>
                {children}
            </div>
        );
    },

    // return a cloned Section object with click tracking and 'active' awareness
    enhanceSection: function (child) {

        const selectedId = this.state.selected;
        const id = child.props.id;

        return React.cloneElement(child, {
            key: id,
            // private attributes/methods that the Section component works with
            _selected: id === selectedId,
            _onSelect: this.onSelect
        });
    },

    // when this section is selected, inform the parent Accordion component
    onSelect: function (id) {
        this.setState({selected: id});
    }
});


module.exports = Accordion;

and the AccordionSection component looks like so:

const React = require('react');


const AccordionSection = React.createClass({

    render: function () {

        const className = 'accordion-section' + (this.props._selected ? ' selected' : '');

        return (
            <div className={className}>
                <h3 onClick={this.onSelect}>
                    {this.props.title}
                </h3>
                <div className='body'>
                    {this.props.children}
                </div>
            </div>
        );
    },

    onSelect: function (e) {
        console.log('event:',e);
        // tell the parent Accordion component that this section was selected
        this.props._onSelect(this.props.id);
    }
});



module.exports = AccordionSection;

everything works, and the CSS is working, but the problem is that the onClick doesn't get registered. So clicking on the accordion elements does nothing. Does anyone know why the onClick handler might not get registered in this situation?

Alexander Mills
  • 90,741
  • 139
  • 482
  • 817

2 Answers2

14

React DOM render to string only sends the initial HTML as a string without any JS.
You need a client side react router as well which will attach the required JS handlers to the HTML based on their react-id's. The JS needs to run on both sides.
Universal rendering boilerplate for quick start. https://github.com/erikras/react-redux-universal-hot-example
Another question which is similar to yours. React.js Serverside rendering and Event Handlers

Community
  • 1
  • 1
Jeff P Chacko
  • 4,908
  • 4
  • 24
  • 32
6

None of the hooks will register with ReactDOMServer.RenderToString. If you want to accomplish server side rendering + hooks on your react component, you could bundle it on the client (webpack, gulp, whatever), and then also use ReactDOMServer.RenderToString on the server.

Here's a blog post that helped me accomplish this: https://www.terlici.com/2015/03/18/fast-react-loading-server-rendering.html