- React半科普文
- 什么是React
- getting started
- 文件分离
- Server端编译
- 定义一个组件
- 使用property
- 组件嵌套
- 组件更新
- Virtual DOM
- react native
什么是React
以下是官方定义,反正我是没看懂。google了下,大家都称之“前端UI开发框架”,勉强这么叫着吧。可以看下这篇文章对react的介绍,本文更多的是覆盖react的入门实践。
A JAVASCRIPT LIBRARY FOR BUILDING USER INTERFACES
本文提到的例子可以在这里找到:github链接
getting started
getting-started.html
里的例子比较简单,首先引入 react.js
、JSXTransformer.js
,然后通过 React.render()
方法即可。语法细节什么的可以先不管。
需要注意的点是,最后一段script标签,上面声明了 type="text/jsx"
,也就是说并不是通常的直接解析执行的脚本,JSXTransformer.js
会对其进行预编译后再执行。
<!DOCTYPE html> <html> <head> <title>getting started</title> <script src="build/react.js"></script> <script src="build/JSXTransformer.js"></script> </head> <body> <div id="example"></div> <script type="text/jsx"> React.render( <h1>Hello, world!</h1>, document.getElementById(‘example‘) ); </script> </body> </html>
好了,看下效果吧。
文件分离
根据以往养成的好习惯,直觉的感觉到,这里应该将组件的定义跟 html 页面分离,不然以后页面肯定就乱糟糟了。示例请查看 separate-file.html
修改后的html文件,瞬间清爽很多。同样需要注意 type="text/jsx"
<!DOCTYPE html> <html> <head> <title>demo</title> <script src="build/react.js"></script> <script src="build/JSXTransformer.js"></script> </head> <body> <div id="example"></div> <script type="text/jsx" src="js/helloworld.js"></script> </body> </html>
处理后的 helloworld.js
,其实内容一点变化都没有
React.render( <h1>Hello, world!</h1>, document.getElementById(‘example‘) );
好了,查看效果。双击 separate-file.html
,这时看到页面是空白的,同时控制台还有错误信息。
肿么办呢?相信有经验的兄弟知道咋整了。这里偷个懒,直接用fis
起个本地服务器。在2015.04.09-react/
根路径下运行
fis server start fis release
然后访问 http://127.0.0.1:8080/separate-file.html。well done
Server端编译
之前提到,JSXTransformer.js
会对标志 type="text/jsx"
的script 进行预编译后再执行,那么在浏览器端很可能就会遇到性能问题(没验证过)。React 的开发团队当然也考虑到这个问题了,于是也提供了server端的编译工具。
请查看 server-build-without-transform.html
。这里我们已经把 JSXTransformer.js
的依赖去掉。相对应的,我们需要在server端做一定的编译工作。
<!DOCTYPE html> <html> <head> <title>demo</title> <script src="build/react.js"></script> <!-- <script src="build/JSXTransformer.js"></script> --> </head> <body> <div id="example"></div> <script src="js-build/helloworld.js"></script> </body> </html>
挺简单的,安装 react-tools
,然后运行相应命令即可
npm install -g react-tools
jsx --watch js/ js-build/
可以看到,js/helloworld.js
已经被编译成 js-build/helloworld.js
。我们看下编译后的文件
编译后的文件。可以看到,都是浏览器可以理解的语法。你也可以一开始就这样编写,不过保证你会抓狂。
React.render( React.createElement("h1", null, "Hello, world!"), document.getElementById(‘example‘) );
定义一个组件
下面定义一个极简的组件 来做说明,示例代码可以查看 define-a-component.html
。从代码可以看到:
- 通过
React.createClass()
来定义一个组件,该方法需要定义render
方法来返回组件对应的 dom 结构 - 通过
React.render()
来调用组件。该方法传入两个参数,分别是 对应的组件,父级节点。
<!DOCTYPE html> <html> <head> <title>getting started</title> <script src="build/react.js"></script> <script src="build/JSXTransformer.js"></script> </head> <body> <div id="example"></div> <script type="text/jsx"> var HelloComponent = React.createClass({ render: function(){ return ( <div> <h1>Hello World</h1> <p>I am Hello World Component</p> </div> ); } }); React.render( <HelloComponent />, document.getElementById(‘example‘) ); </script> </body> </html>
示例效果如下:
刚接触React组件定义的同学,可能会踩中下面的坑。比如把前面的组件定义改成。区别在于去掉了组件最外层的包裹节点 <div>
var HelloComponent = React.createClass({ render: function(){ return ( <h1>Hello World</h1> <p>I am Hello World Component</p> ); } });
再次访问 http://127.0.0.1:8080/define-a-component.html 会有如下错误提示。错误信息比较明确了,不再赘述,乖乖加上包裹节点就好了
使用property
在定义一个组件时,我们通常会暴露一定的配置项,提高组件的可复用性。这里简单示范下如何实现,具体代码可查看 using-properties.html
。
关键代码如下,还是比较直观的。使用组件时,就跟使用浏览器内置的组件那样给属性赋值。在组件定义的内部代码实现中,通过 this.props.xx
来取到对应的值即可。
<script type="text/jsx"> var HelloComponent = React.createClass({ render: function(){ return ( <div> <h1>Title is: {this.props.title}</h1> <p>Content is: {this.props.content}</p> </div> ); } }); React.render( <HelloComponent title="hello" content="world" />, document.getElementById(‘example‘) ); </script>
组件嵌套
推荐看下 Thinking in React 这篇文章。要实现文中提到的 搭积木式的开发模式,组件的嵌套使用是必不可少的。下面示范下,具体代码查看 compose-components.html
。
<!DOCTYPE html> <html> <head> <title>demo</title> <script src="build/react.js"></script> <script src="build/JSXTransformer.js"></script> </head> <body> <div id="example"></div> <script type="text/jsx"> var Title = React.createClass({ render: function(){ return ( <h1>This is Title</h1> ); } }); var Content = React.createClass({ render: function(){ return ( <p>This is Content</p> ); } }); // Article组件包含了 Title、Content 组件 var Article = React.createClass({ render: function() { return ( <div class="article"> <Title /> <Content /> </div> ); } }); React.render( <Article />, document.getElementById(‘example‘) ); </script> </body> </html>
组件更新
在React的体系中,组件的UI会随着组件状态的变化(state)进行更新。从围观的代码层面来说,是 setState()
方法被调用时,组件的UI会刷新。简单例子可以参考 update-if-state-chagne.html
。例子可能不是很恰当,就表达那么个意思。
其中有两个方法简单介绍下:
getInitialState
:返回组件的初始状态。componentDidMount
:当组件渲染完成后调用的方法。
ps:React的组件更新机制是最大的亮点之一。看似全量刷新,实际内部是基于Virtual DOM机制的局部刷新,开发者无需再编写大量的重复代码来更新局部的dom节点。
Virtual DOM以及局部刷新实现机制,这里就不展开了,可参考 http://calendar.perfplanet.com/2013/diff/
<!DOCTYPE html> <html> <head> <title>demo</title> <script src="build/react.js"></script> <script src="build/JSXTransformer.js"></script> </head> <body> <div id="example"></div> <script type="text/jsx"> var HelloComponent = React.createClass({ getInitialState: function(){ return { title: ‘title1‘, content: ‘content1‘ }; }, componentDidMount: function(){ var that = this; setTimeout(function(){ that.setState({ title:‘title2‘, content:‘content2‘ }); }, 2000); }, render: function(){ return ( <div> <h1>Title is: {this.state.title}</h1> <p>Content is: {this.state.content}</p> </div> ); } }); React.render( <HelloComponent />, document.getElementById(‘example‘) ); </script> </body> </html>
访问 http://127.0.0.1:8080/update-if-state-chage.html ,刚打开时,展示如下
2000ms后,界面刷新。
Virtual DOM
已经有人写过了,这里直接附上参考链接:http://calendar.perfplanet.com/2013/diff/
react native
TODO 待填坑