[英]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.