Cannot read property '__reactAutoBindMap' of undefined
Asked Answered
R

2

9

For the last week now I've been completely at a loss for how to set up server side rendering with React. This is a new project but it's an express server and I'm attempting to render just a super simple hello world react app which uses react-router-component..

I think the best way for me to get some help is to share the code I have right now and I'm hoping somebody can please tell me what I'm doing wrong! I've followed tutorial after tutorial and tried all sorts of different things but I keep getting error after error!

This is my app.js for the express server, the relevant code is the * route if you scroll down a bit:

require('node-jsx').install({extension: '.jsx'});
var React = require('react');

var App = require('./src/App.jsx');

var request = require('superagent');
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var url = require('url');

//Database and Passport requires
var mongoose = require('mongoose');
var passport = require('passport');
var LocalStrategy = require('passport-local');

// var api = require('./routes/api');

var app = express();

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(require('express-session')({
  secret: 'secret',
  resave: false,
  saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static(path.join(__dirname, 'public')));

//passport config
var Account = require('./models/account');
passport.use(new LocalStrategy(Account.authenticate()));
passport.serializeUser(Account.serializeUser());
passport.deserializeUser(Account.deserializeUser());

//mongoose
mongoose.connect('mongodb://localhost/database');

//THIS is the relevant section that renders React and sends to client
app.get('*', function(req, res, next){
  var path = url.parse(req.url).pathname;
  React.renderToString(
    React.createFactory(App({path : path})),
    function(err, markup) {
      res.send('<!DOCTYPE html>' + markup);
    }
  );
});


// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});


module.exports = app;

the App.jsx file being required in the app.js file:

/**
 * @jsx React.DOM
 */

var React = require('react');
var Router = require('react-router-component');
var Locations = Router.Locations;
var Location = Router.Location;
var Index = require('./components/Index.jsx');


var App = React.createClass({
    render: function() {
        return (
              <html>
                <head lang="en">
                    <meta charSet="UTF-8"/>
                    <title>React App</title>
                </head>
                <body>
                    <div id="main">
                        <Locations path={this.props.path}>
                            <Location path="/" handler={Index} />
                        </Locations>
                    </div>
                    <script type="text/javascript" src="./javascripts/bundle.js"></script>
                </body>
               </html>
        )
    }
});

module.exports = App;

and the Index.jsx file required in the App.jsx:

var React = require('react');

 var Index = React.createClass({
    render: function() {
        return (
        <div className="test">
            <span>Whats going on</span>
        </div>
        )
    }
 });

 module.exports = Index; 

I'm only showing you my most recent attempt at getting this to work here but rest assured I've tried all different methods to render a react component, such as renderComponentToString, I've also tried React.renderToString(React.createElement(App)) etc etc..

But now I keep getting this error "Cannot read property '__reactAutoBindMap' of undefined"

Please Help!!! :) Thanks

Rascality answered 28/3, 2015 at 17:36 Comment(3)
React.createFactory(App({path : path})) should be: React.createElement(App({path : path}))Clapper
Close, but props must be passed as the second argument to React.createElement. React.createElement(App, {path : path})Divisionism
as @Morhaus said - moving the props to the second argument fixed this error for me in v0.13.Cyril
L
13

I have nearly the same problem. I had:

 React.render(AppTag(config), node);

Where AppTag was require() to JSX file. And this generate me "Cannot read property '__reactAutoBindMap' of undefined"

I try few things, but only this solved my problem:

 React.render(React.createElement(AppTag, config), node);

I hope this will be helpful

I tried more things, this also works:

 React.render(React.createFactory(AppTag)(config), node)
Leibowitz answered 3/4, 2015 at 10:2 Comment(1)
rendering static markup on the server, this worked for me: var appHtml = ReactDOMServer.renderToStaticMarkup(React.createFactory(App)());Confessional
S
4

In react v 0.12.* you will get the following warning:

Warning: Something is calling a React component directly. Use a factory or JSX instead. See: http://fb.me/react-legacyfactory

The link states that your code is calling your component as a plain function call, which is now deprecated

However, when you update to react v 0.13.*, this, will no longer work

You will have 2 options to upgrade:

Using JSX

React components can no longer be called directly like this. Instead you can use JSX:

var React = require('react');
var MyComponent = require('MyComponent');

function render() {
  return <MyComponent foo="bar" />;
}

Without JSX

If you don't want to, or can't use JSX, then you need to wrap your component in a factory before calling it

var React = require('react');
var MyComponent = React.createFactory(require('MyComponent'));

function render() {
  return MyComponent({ foo: 'bar' });
}

Or you can create the element inline

function render(MyComponent) {
  return React.createElement(MyComponent, { foo: 'bar' });
}
Splenitis answered 9/6, 2015 at 0:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.