简体   繁体   English

同构React-如何使React函数成为窗口对象的一部分

[英]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. 我一直在使用node-jsx,browserify,reactify等构建同构的react应用。我的代码在服务器上运行良好,并且组件已正确安装和呈现。 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. 但是,react函数似乎不起作用,例如,handleClick函数无法识别alert(),或者console.log()永远不会在服务器或客户端控制台上都输出预期的结果。 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. 更新:我想指出的另一件事是,当我运行服务器并转到浏览器时,在浏览器控制台(使用chrome dev工具)中键入“ window.React”,它实际上返回了React对象。 But console.log still doesn't do anything for click handler function. 但是console.log对于点击处理程序功能仍然不起作用。

views/index.ejs 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 路线/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 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 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 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. 无论您想使它在全球范围内可用,通常都需要对ReactDOM做同样的事情,以便可以直接在html文件中调用render。 It's not usually recommended though. 通常不建议这样做。 You might want to use the standalone downloads from React Downloads . 您可能要使用React Downloads中的独立下载

document.getElementById('react-main-mount'); returns null if your script runs before that element is loaded in html. 如果脚本在HTML中加载该元素之前运行,则返回null。

What you should do is either include your script before the closing tag </body> , or run ReactDOM.render after DOMContentLoaded . 您应该做的是在结束标记</body>之前添加脚本,或者在DOMContentLoaded之后运行ReactDOM.render

So I realized it has something to do with React.render in the main.js file. 所以我意识到它与main.js文件中的React.render有关。 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. 在这种情况下,不需要渲染TableComponent,也需要在不使用插件的情况下进行React。

It works now. 现在可以使用了。 Thanks for everyone's help! 感谢大家的帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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