因为用React就会需要写jsx。
React会将jsx编译成js。然后append到head当中。从fiddler的请求和JSXTransformer源码来看,当在页面使用下面的html时候:
会发送两次请求react_test.js文件,一次是JSXTransformer发送的,一次是浏览器识别script标签自动发送的。
上面的react_test.js里面全是jsx语法,和javascript有点像,如:
var Timer = React.createClass({ getInitialState: function() { return {secondsElapsed: 0}; }, tick: function() { this.setState({secondsElapsed: this.state.secondsElapsed + 1}); }, componentDidMount: function() { this.interval = setInterval(this.tick, 1000); }, componentWillUnmount: function() { clearInterval(this.interval); }, render: function() { return (Seconds Elapsed: {this.state.secondsElapsed}); } });
React.render(, document.getElementById('timerExample'));
现在问题来了:
上面打印的信息的是undefined。所以迫切地希望能够有个这样的事件,这样就能拿到Timer,也就能够调用它的相关方法:
React.jsReady(function () { console.log(Timer) //希望这里可以拿到Timer })
主要是为了让封装的多个组件能够更加直接的调用,希望jsx以外的js文件能够拿到jsx内部定义的对象,或者React.render的返回值(React.render的返回值就是该对象的实例)。如:
var tt=React.render(, document.getElementById('timerExample'));
上面的tt其实就是Timer的实例(也就是new Timer..)。 需要监听jsx已经编译执行完成,编译执行完成就可以使用jsx内部的变量。那么如果扩展?
(function (root, factory) { if (typeof define === 'function' && define.amd) { define(['react', "JSXTransformer"], factory); } else if (typeof exports === 'object') { module.exports = factory(require('react'), require('JSXTransformer')); } else { root.returnExports = factory(root.React, root.JSXTransformer); } }(this, function (React, JSXTransformer) { React.jsReady = function (fn) { React.jsReady._readyCallbacks.push(fn); } React.jsReady._readyCallbacks = []; if (window.addEventListener) { window.addEventListener('DOMContentLoaded', runScripts, false); } else { window.attachEvent('onload', runScripts); } function runScripts() { JSXTransformer.runScripts(React.jsReady._readyCallbacks); } }));
上面是UMD的写法,据说现在已经有AMD\CMD\UMD\KMD了 = =!
第一步:在react和JSXTransformer下方引用react_jsready.js
第二步:注释掉JSXTransformer.js中的
if (window.addEventListener) { window.addEventListener('DOMContentLoaded', runScripts, false); } else { window.attachEvent('onload', runScripts); }
第三步:JSXTransformer.js中
//171行加上 var _loadedScriptCount = 0; //run方法加上(180行左右) if (_loadedScriptCount === count) { var i = 0, len = callbacks.length; for (; i < len; i++) { callbacks[i](); } } //270行左右 load(script.src, function(content) { result[i].loaded = true; result[i].content = content; _loadedScriptCount++; check(); }, function() { result[i].error = true; _loadedScriptCount++; check(); }); } else { _loadedScriptCount++; ... ...
这里就不依依列举了,下方了提供演示地址,可自行下载JSXTransformer.js。
这里的基本原理就是计数,当执行了的jsx和页面的jsx(包括页面内嵌和外链的)的个数相等的时候,去执行注册的回调函数。
这里需要注意的是:如果不需要jsready这功能,也需要引用该js,因为已经把JSXTransformer.js中的runScripts禁用掉了暴露给外部调用:),改由jsready触发。
点击这里: jsready demo
React的Class base的风格还是非常讨人喜欢的,自我感觉jsready这个特性非常重要,刚接触reactjs半天= =!,欢迎吐槽:)