react 的核心思想是:封装组件,各个组件维护自己的状态和 ui,当状态变更,自动重新渲染整个组件。
首先react值得拍手称赞的是它所有的开发都基于组件(component),然后组件和组件之间通过props传递方法,每个组件都有一个状态(state),当某个方法改变了这个状态值时,整个组件就会重绘,从而达到刷新。另外,说到重绘就要提到虚拟dom了,就是用js模拟dom结构,等整个组件的dom更新完毕,才渲染到页面,简单来说只更新了相比之前改变了的部分,而不是全部刷新,所以效率很高。
大家先新建一个项目文件夹,在里面建一个项目信息的文件<code>package.json</code>:
建好之后,运行命令:
上面的文件可以看到:入口文件是在src文件夹里的entry.js,然后输出文件放在out文件夹的bundle.js里。externals属性是告诉webpack当遇到require('react')的时候,不去处理并且默认为全局的react变量。这样子,我们就需要在index.html单独用src去加载js。最后看看配置的loaders:
因为我们js文件会使用jsx和es6的语法,所以使用<code>jsx-loader</code>和<code>babel-loader</code>来编译js文件。
scss文件使用<code>sass-loader</code>编译成css文件。
写的时候可以省略-loader,多个loader使用<code>!</code>连接。
先来看一下项目的目录结构,最重要的就是src目录:
<code>index.html</code>是项目的入口页面。
<code>components</code>文件夹存放项目拆分出来的各个组件文件。
<code>vendor</code>文件夹存放项目依赖的框架,这里只有react。
先来看index.html:
entry.js :
webpack会将入口文件进行合并和整理,最后输出一个bundle.js,所以所有的逻辑都在这个js文件中,因此在index.html中,只需要引入react框架和bundle.js就好了。
这个todo的项目,我们可以分为三个部分:头部,中间部分,尾部。那我们就来逐一的分析一下这些组件:
我们知道react的主流思想就是,所有的state状态和方法都是由父组件控制,然后通过props传递给子组件,形成一个单方向的数据链路,保持各组件的状态一致。所以我们在这个父组件app上,看的东西稍微有点多。一点点来看:
它采用es6的语法来创建了一个<code>继承react.components的app类</code>。
然后在构造函数里定义了自己的<code>状态state</code>。
然后定义了很多方法,后面通过<code>props传递给子组件</code>。
最后定义组件自己的渲染方法<code>render</code>。
在app组件的构造函数里,我们初始化了组件的state,分别有两个,一个是todos的列表,一个是所有的todos是否全选的状态。在渲染的时候,我们会把状态传递到子组件中,如果子组件的某一个方法让状态发生了改变,那么整个组件就会进行重绘。
从上面的渲染(render)方法可以看出,组件的结构分为三部分,就是上中下。上面的<code>todoheader</code>是用来输入任务的地方,中间的<code>todomain</code>是用来展示任务列表的, 下面的<code>todofooter</code>提供一些特殊的方法,比如全选、删除等。
app组件定义的方法,会在渲染的时候传递给子组件,比如todoheader组件:
说明:
通过props传递子组件需要的值和方法。
传递方法时一定要bind(this),不然内部this会指向不正确。
子组件的标签使用的时候一定要使用<code>/</code>闭合起来。
es6语法,spread操作符让代码简洁很多,如上述代码中的todofooter:
把上面的app组件的内容渲染到id为'app'的dom元素里。
然后我们再简单看一下分解出来的三个组件:<code>todoheader</code>, <code>todomain</code>, <code>todofooter</code>。
todoheader组件的创建方法和app组件的创建方法一样,内部方法就少了很多了,这里就定义了一个监听键盘的方法,绑定到了输入框的keyup事件上,敲击回车键的时候就会调用父组件传过来的<code>addtodo()方法</code>。
todomain组件主要是为了把传递过来的todos列表遍历显示出来,而每一个list又是一个todoitem组件。这里又用到了spread操作符<code>{...this.props}</code>,代码中也做了注释,可以洗洗品味一下。
todoitem有这四个方法,我们主要看看新出现的几点:
<code>react.finddomnode(this)</code>可以获取当前这个组件标签。
在元素中定义<code>ref=xxx</code>属性,就可以通过<code>react.finddomnode(this.refs.xxx)</code>获取到这个元素。
给元素定义class类名的时候要使用<code>classname</code>。
todofooter组件主要用来批量更改状态和清除已完成的任务,还要显示任务完成情况,所以代码很简单了。
回过头来再看看这个demo的实现过程,react组件化的思想让我们编写代码的时候思维清晰,便于阅读。我们通过父组件来控制状态,并通过props传递,来保证组件内的状态一致,并且我们可以清晰的看到某一个方法该由谁来维护。这是一种全新的前端编码体验,相信以后会成为主流。
另外,我们看到代码中,html直接嵌到js中了,这就是react提出的一种叫jsx的语法。其实入门react本身还是很简单,只是很多人看到jsx和es6的语法,就打了退堂鼓了,因为我们被代码分离“洗脑”太久了。其实,它们就好像是一堵墙,要是我们畏惧这个障碍止步不前,那么只能停留在原地,如果我们骨气勇气爬上去,才发现react的风景真的很优美!
ps: 本人刚开始学习react,如果有理解不对的地方,望各位前辈指出!
参考资料:
<a href="http://www.reqianduan.com/2297.html">http://www.reqianduan.com/2297.html</a>
<a href="http://wiki.jikexueyuan.com/project/react-tutorial/">http://wiki.jikexueyuan.com/project/react-tutorial/</a>
<a href="http://gank.io/post/564151c1f1df1210001c9161">http://gank.io/post/564151c1f1df1210001c9161</a>
来自:阿里技术协会
作者:义坤