简体   繁体   中英

Isomorphic React - how to make react function as part of the window object

I've been building an isomorphic react app using node-jsx, browserify, reactify, etc. My code runs fine on the server, and components are mounted and rendered correctly. However, the react function doesn't seem to work, for instance, the handleClick function does not recognize alert(), or console.log() never prints out expected result on neither the server nor the client side console. Can anyone identify what's going on here?

UPDATE: Another thing I want to point out is, when I run the server and go to the browser, in the browser console(used chrome dev tool) I typed "window.React", it actually returned the React object. But console.log still doesn't do anything for click handler function.

views/index.ejs

<!doctype html>
<html>
<head>
    <title>Shortened URL Generator</title>
    <link href='/style.css' rel="stylesheet">
    <link href="css/griddle.css" rel="stylesheet" />
</head>
<body>
<h1 id="main-title">Welcome to Shortened URL Generator</h1>

<div id="react-main-mount">
    <%- reactOutput %>
</div>

<!-- comment out main.js to see server side only rendering -->
<script src="https://fb.me/react-with-addons-0.14.3.min.js"></script>
<script src="https://fb.me/react-dom-0.14.3.min.js"></script>
<script src="/main.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"></script>
<script src="//fb.me/JSXTransformer-0.12.0.js"></script>
<script type="text/javascript" src="scripts/griddle.js"></script>

</body>
</html>

routes/routes.js

    var React = require('react/addons'),
    ReactApp = React.createFactory(require('../components/ReactApp'));

    module.exports = function(app) {
    var storeUrls = {
        "fb.com": "facebook.com"
    };
    app.get('/', function(req, res){
        // React.renderToString takes your component
        // and generates the markup
        var reactHtml = React.renderToString(ReactApp({}));
        // Output html rendered by react
        // console.log(myAppHtml);
        res.render('index.ejs', {reactOutput: reactHtml});
    });
    app.get('/:routeParam', function(req, res){

    });

};

app/components/ReactApp.js

var TableComponent = require('./TableComponent');
var React = require('react/addons');
var urls = require('./url');
var Griddle = React.createFactory(require('griddle-react'));
var ReactApp = React.createClass({

componentDidMount: function () {
    console.log("yes");

},
handleClick: function() {
   // this.setState({liked: !this.state.liked});
    var longUrl = this.refs.inputUrl;
    urls.push({
        "original url": longUrl,
        "shortened url": "/"
    })
    console.log(longurl);

},
render: function () {
    return (
        <div>
        <div id="form">
            <form>
             <section>Paste your long url here</section>
             <input ref="inputUrl"  value={this.props.value} type="text" placeholder="http://...." />
             <button onclick={this.handleClick} type="submit" value="Submit">Shorten URL</button>
            </form>
        </div>
            <div id="table-area">
                <TableComponent />
            </div>
        </div>
    )
}
});

module.exports = ReactApp;

app/main.js

var React = require('react/addons');
var ReactApp = require('./components/ReactApp');
var TableComponent = require('./components/TableComponent');

var mountNode = document.getElementById('react-main-mount');
var mountTable= document.getElementById('table-area');

React.render(new ReactApp({}), mountNode);
React.render(new TableComponent({}), mountTable);

server.js

var express = require('express'),
path = require('path'),
app = express(),
port = 5000,
bodyParser = require('body-parser');

require('node-jsx').install();


// Include static assets. Not advised for production
app.use(express.static(path.join(__dirname, 'public')));
// Set view path
app.set('views', path.join(__dirname, 'views'));
// set up ejs for templating. You can use whatever
app.set('view engine', 'ejs');

// Set up Routes for the application
require('./app/routes/routes.js')(app);

//Route not found -- Set 404
app.get('*', function(req, res) {
    res.json({
    'route': 'Sorry this page does not exist!'
});
});

app.listen(port);
console.log('Server is Up and Running at Port : ' + port);

Gulpfile.js

var gulp = require('gulp'); var source = require('vinyl-source-stream'), browserify = require('browserify'); gulp.task('scripts', function(){ return browserify({ transform: [ 'reactify' ], entries: 'app/main.js' }) .bundle() .pipe(source('main.js')) .pipe(gulp.dest('./public/')); }); gulp.task('default', ['scripts']);

It can be a simple modification to your existing code:

if (typeof window !== 'undefined) {
    window.React = require('react');
}

Do that for whatever you want make available globally, usually you'll want to do the same for ReactDOM too so you can call render directly in a html file. It's not usually recommended though. You might want to use the standalone downloads from React Downloads .

document.getElementById('react-main-mount'); returns null if your script runs before that element is loaded in html.

What you should do is either include your script before the closing tag </body> , or run ReactDOM.render after DOMContentLoaded .

So I realized it has something to do with React.render in the main.js file. instead of

React.render(new ReactApp({}), mountNode);

it should be

React.render(<ReactApp/>, document.getElementById('react-main-mount'));

In this case, TableComponent does not need to be rendered, also require React without using the addon.

It works now. Thanks for everyone's help!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM