ReactJS入门学习二
阅读目录
React的背景和基本原理
在web开发中,我们总需要将变化的数据实时反应到UI上,这时就需要对DOM进行操作,复杂或频繁的对DOM操作是性能瓶颈产生的原因,React为此引入了虚拟的DOM的机制,在浏览器端使用javascript实现了一套DOM API,基于React开发时所有的DOM构造都是通过虚拟的DOM进行的,每当数据有变化时,React都会重新构建整个DOM树,然后React将当前的整个DOM树与之前的DOM树进行对比,得到变化的部分,然后将变化的部分进行实际的浏览器的DOM更新,而且React能够批处理虚拟的DOM刷新,在一个事件循环内的两次数据的变化会被合并,比如你连续先将节点内容A变成B,然后将B变成A,React会认为UI不发生任何变化。尽管每一次都需要构造完整的虚拟DOM树,但是虚拟DOM树是内存数据,性能是非常高的,而对实际的DOM进行操作仅仅是Diff部分,因此可以提高性能。在保证性能的同时,我们将不再需要关注某个数据的变化如何更新到一个或者多个具体的DOM元素,而只需要关心在任意一个数据状态下,整个界面是如何Render的。
React组件化:
虚拟DOM不仅带来了简单的UI开发逻辑,同时也带来了组件开发的思想,所谓组件,即封装起来的具有独立功能的UI部件,React推荐以组件的方式去重写思考UI构成,将UI上的每一个功能相对独立的模块定义成组件。然后将小组件通过嵌套的方式变成大组件,最终构成完整的UI构建。如果说MVC的思想让我们做到表现,数据,控制的分离,那么React则以组件化的思考方式则带来了UI模块间的分离,比如我上一篇文章介绍的网站页面一样:如下图:
导航条,侧边栏及内容区分别为不同的小组件通过嵌套的方式变成一个完整的UI界面构建。
React组件应该有如下特征:
- 可组合:一个组件易于与其他组件一起使用,或者说嵌套在另一个组件内部。
- 可重用:每个组件都具有独立的功能,它可以被使用在多个UI场景。
- 可维护:每个小的组件仅仅包含自身的逻辑,更容易理解及维护。
下面我们首先使用React时候需要引用如下JS,react.js和JSXTransformer.js,下面的HTML代码如下:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="js/react.js"></script>
<script src="js/JSXTransformer.js"></script>
</head>
<body>
<div id = "demo"></div>
<script type="text/jsx">
// code
</script>
</body>
</html>
理解React.render()
React.render()是用于将模版转为HTML语言,并且插入指定的DOM节点。
如下代码:
React.render(
<h1>hello,world!</h1>,
document.getElementById("demo")
);
页面生成HTML结构如下:
页面显示如下:
什么是JSX?
React的核心机制就是实现了一个虚拟DOM,利用虚拟DOM来减少对实际DOM的操作从而提升性能,组件DOM结构就是映射到这个虚拟的DOM上,React在这个虚拟DOM上实现了一个diff算法,当要更新组件的时候,会通过diff寻找要变更的DOM节点,再把这个修改更新到浏览器实际的DOM节点上,所以实际上不是真的渲染整个DOM树,这个虚拟的DOM是一个纯粹的JS数据结构,所以性能比原生DOM会提高很多;
虚拟DOM也可以通过Javascript来创建,比如如下代码:
var child1 = React.createElement('li',null,'First Text Content');
var child2 = React.createElement('li',null,'second Text Content');
var root = React.createElement('ul',{className:'test'},child1,child2); React.render(root,document.getElementById("demo"));
在页面中渲染成结构变成如下:
在页面显示如下:
但是这样编写代码可读性不好,于是React就出现了JSX,使用如下的方式创建虚拟DOM;
var root = (
<ul className="test">
<li>First Text Content</li>
<li>second Text Content</li>
</ul>
);
React.render(root,document.getElementById("demo"));
上面2种方式实现的效果都一样,可能很多人会认为引入一个JSX的源码进来会影响页面性能,在这里我们只是为了测试而已,如果真的在开发项目中,JSX在产品打包阶段会编译成纯粹的javascript,JSX语法不会带来任何性能影响的。
为什么要使用JSX?
前端开发最基本的功能是展示数据,因此很多框架都引入了模版引擎,如果我们不使用模版的话,那么我们需要手动并接一个很长的html字符串,并且这样并接很容易出错,代码也不太美观,且最重要的是展示逻辑和业务逻辑没有得到足够的分离(使用MVC思想考虑);因此React就发明了JSX;
JSX的语法
JSX允许HTML与javascript混写,如下代码:
var names = ['longen1','longen2','longen3'];
React.render(
<div className="aa">
{
names.map(function(name){
return <p>Hello,{name}</p>
})
}
</div>,document.getElementById("demo")
);
JSX的语法规则是:遇到HTML标签(以<开头),就是用HTML的规则解析,遇到代码块(以{开头),就用jSX的语法规则解析;上面的代码生成如下:
理解this.props
Props表示的是组件自身的属性,是父层节点传递给子层节点的一些属性或者数据,如下代码:
var HelloMessage = React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>;
}
});
React.render(<HelloMessage name="John" />, document.getElementById("demo"));
理解this.props.children
this.props对象的属性与组件的属性一一对应,但是有一个列外,就是this.props.children属性。它表示的是组件的所有子节点;
如下代码:
var NotesList = React.createClass({
render: function() {
return (
<ol>
{
this.props.children.map(function (child) {
return <li>{child}</li>
})
}
</ol>
);
}
});
React.render(
<NotesList>
<span>hello</span>
<span>world</span>
</NotesList>,
document.getElementById("demo")
);
在页面显示如下:
理解React.createClass方法
React允许将代码封装成组件,然后像普通的HTML一样插入,React.createClass方法用于生成一个组件类;如下代码:
var NodeList = React.createClass({
render: function() {
return <h1>Hello {this.props.name}</h1>;
}
});
React.render(
<NodeList name="John" />,
document.getElementById('demo')
);
如上代码;NodeList就是一个组件类,模版插入<NodeList />时,会自动生成一个NodeList的实列;所有组件都必须有一个render()方法,用于输出组件;如上<NodeList name=”John”/>就是加入了一个属性name,组件上的属性我们可以使用this.props对象上获取,比如上面的name属性就可以通过this.props.name读取;
在页面显示如下:
理解this.state
this.state是组件私有的,我们可以通过this.setState()来改变它,那么组件会重新渲染下自己;如下代码:
var LikeButton = React.createClass({
getInitialState: function() {
return {liked: false};
},
handleClick: function(event) {
this.setState({liked: !this.state.liked});
},
render: function() {
var text = this.state.liked ? 'like' : 'haven\'t liked';
return (
<p onClick={this.handleClick}>
You {text} this. Click to toggle.
</p>
);
}
});
React.render(
<LikeButton />,
document.getElementById('demo')
);
如上代码 先使用 getInitialState() 方法用于定义初始状态(且只执行一次),当用户点击时候,调用handleClick函数,使用this.setState来动态的更改值,每次更改后,会自动调用render()进行渲染组件。
this.props与this.state的区别?
this.props是指属性从父节点元素继承过来的,且属性不可以更改的。
this.state 是指可以动态更改的;是组件的私有的;
Refs和findDOMNode()
为了同浏览器交互,我们有时候需要获取真实的DOM节点,我们可以通过React的 React.findDOMNode(component)获取到组件中真实的DOM;
如下代码:
var MyComponent = React.createClass({
handleClick: function() {
React.findDOMNode(this.refs.myTextInput).focus();
},
render: function() {
return (
<div>
<input type="text" ref="myTextInput" />
<input
type="button"
value="Focus the text input"
onClick={this.handleClick}
/>
</div>
);
}
});
React.render(
<MyComponent />,
document.getElementById('demo')
);
组件MyComponent的子节点有一个文本输入框,点击按钮后,把焦点放在输入框内,这时候我们需要先获取到MyComponent组件内的真实的DOM节点,为了做到这点,文本输入框必须有一个ref属性,然后 this.refs.[refName]就指向与这个虚拟的DOM子节点,最后通过React.findDOMNode获取真实的DOM节点。
理解React.createElement
参数:type(string), config(object), children(子节点)
如下代码
var CommentBox = React.createClass({
displayName: 'CommentBox',
render: function(){
return (
React.createElement('div',{className:'commentBox'},"Hello,world!I am a CommentBox")
);
}
});
React.render(
React.createElement(CommentBox,null),document.getElementById("demo")
);
在页面上显示如下:
理解React.PropTypes
验证使用组件时,提供的参数是否符合要求,组件的属性可以接受任意值,字符串,对象,函数都可以;比如如下代码,验证组件中的 title属性是否是字符串;如下代码:
var MyTitle = React.createClass({
propTypes: {
title: React.PropTypes.string.isRequired
},
render: function() {
return this.props.title == 1234 ? <p>是一个字符串</p> : null
}
});
var data = "123";
React.render(
<MyTitle title="1234" />,document.getElementById("demo")
);
可以看到,在页面打印出是一个字符串;
理解React.isValidElement
参数object
判断参数是否是一个合法的的ReactElement,并返回Boolean值;如下代码测试
var Longen = React.createClass({
render: function() {
return <p>123</p>
}
});
var test = <Longen/>,
test2 = '<Longen/>';
console.log(React.isValidElement(test)); //true
console.log(React.isValidElement(test2)); //false
如何在JSX中如何使用事件
我们以前编写事件如下:
<button onclick="checkAndSubmit(this.form)">Submit</button>
这样编写代码对于简单的html页面时没有问题,但是对于复杂的的页面,我们可以使用如下javascript来绑定事件:我们可以引用jquery;
$('#id').on('click', this.checkAndSubmit.bind(this));
但是在JSX中我们可以如下绑定事件:
<input type="text" value={value} onChange={this.handleChange} />
在JSX中我们不需要关心什么时候去移除事件绑定,因为React会在对应的真实的DOM节点移除就自动解除了事件绑定;
React并不会真正绑定事件到每一个元素上,而是采用事件代理的方式,在根节点document上为每种事件添加唯一的listener,然后通过事件的target找到真实的触发目标元素,这样从触发元素到顶层节点之间的所有节点如果有绑定这个事件的话,React都会触发对应的事件函数,这就是React模拟事件系统的基本原理。
尽管整个事件系统由React管理,但是其API和使用方法与原生事件一致。这种机制确保了跨浏览器的一致性:在所有浏览器(IE9及以上)都可以使用符合W3C标准的API,包括stopPropagation(),preventDefault()等等。对于事件的冒泡(bubble)和捕获(capture)模式也都完全支持。
下面我们来做一个demo,来使用下JSX下的事件如下使用:
var Input = React.createClass({
getInitialState: function() {
return {value: 'Hello!'};
},
handleChange: function(event) {
this.setState({value: event.target.value});
},
render: function () {
var value = this.state.value;
return (
<div>
<input type="text" value={value} onChange={this.handleChange} />
<p>{value}</p>
</div>
);
}
});
React.render(<Input/>, document.getElementById("demo"));
如上是一个input输入框,当我们不断在输入框的值的时候,<p>标签的内容也会跟随的变化;
如何在JSX中如何使用样式
大部分的时候我们都是把样式写到css文件内,但是有时候我们也可以将样式写到JSX中,在JSX中使用样式和真实的样式也很类似,也是通过style属性来定义的,但是和真实DOM不同的是,属性值不能是字符串,而一定要是对象,比如如下:
<div style={{color: '#ff0000', fontSize: '14px'}}>Hello World.</div>
我们可以看到JSX中使用的双大括号,其实第一个大括号的含义是JSX的语法,第二个大括号的含义是一个对象;我们也可以如下写:
var style = {
color: '#ff0000',
fontSize: '14px'
};
<div style={style}>HelloWorld.</div>
ReactJS入门学习二的更多相关文章
-
ReactJS入门学习一
ReactJS入门学习一 阅读目录 React是什么? React如何制作组件? 理解组件属性props 理解页面中如何渲染数据的 理解从服务器端获取数据及理解state的 回到顶部 React是什么 ...
-
SpringMVC入门学习(二)
SpringMVC入门学习(二) ssm框架 springMVC 在上一篇博客中,我简单介绍了一下SpringMVC的环境配置,和简单的使用,今天我们将进一步的学习下Springmvc的操作. mo ...
-
git入门学习(二):新建分支/上传代码/删除分支
一.git新建分支,上传代码到新的不同分支 我要实现的效果,即是多个内容的平行分支:这样做的主要目的是方便统一管理属于同一个内容的不同的项目,互不干扰.如图所示: 前提是我的github上已经有we ...
-
Egg入门学习(二)---理解service作用
在上一篇文章 Egg入门学习一 中,我们简单的了解了Egg是什么东西,且能做什么,这篇文章我们首先来看看官网对Egg的整个框架的约定如下,及约定对应的目录是做什么的,来有个简单的理解,注意:我也是按照 ...
-
ReactJS入门(二)—— 组件的生命周期
如果你熟悉avalon,使用过 data-include-rendered 和 data-include-loaded 等回调方法,那么你会很好地理解React组件的各个生命周期. 说白了其实就是Re ...
-
node入门学习(二)
一.模块系统 1.创建模块和引用模块 //如何创建一个模块 exports.hello = function(){ console.log('hello worl'); }; //这创建了一个模块 / ...
-
dubbo入门学习(二)-----dubbo hello world
一.dubbo hello world入门示例 1.提出需求 某个电商系统,订单服务需要调用用户服务获取某个用户的所有地址: 我们现在需要创建两个服务模块进行测试: 模块 功能 订单服务web模块 创 ...
-
iOS中 Swift初级入门学习(二)
// Copyright (c) 2015年 韩俊强. All rights reserved. // import Foundation /* // 控制语句 // for - in // 遍历字符 ...
-
Objective C 快速入门学习二
Objective-C 类.对象.方法 1.编写一个复数类: #import <Foundation/Foundation.h>@interface Complex: NSObject / ...
随机推荐
-
阿里云+wordpress搭建个人博客网站【小白专用的图文教程】
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
-
SAP Java Connector(JCo)
JCo是一个高性能的,基于JNI的中间件,它实现了SAP的RFC(Remote Function Call)协议. 1.JCo的安装 从 http://files.cnblogs.com/byfhd/ ...
-
XZ压缩
XZ压缩最新压缩率之王 xz这个压缩可能很多都很陌生,不过您可知道xz是绝大数linux默认就带的一个压缩工具. 之前xz使用一直很少,所以几乎没有什么提起. 我是在下载phpmyadmin的时候看到 ...
-
.NET Core2.0+MVC 用Redis/Memory+cookie实现的sso单点登录
之前发布过使用session+cookie实现的单点登录,博主个人用的很不舒服,为什么呢,博主自己测试的时候,通过修改host的方法,在本机发布了三个站点,但是,经过测试,发现,三个站点使用的sess ...
-
mysql 在visual studio中的配置
视图-->其他窗口-->服务器资源管理器-->数据连接-->右键添加连接 servername:localhost username:root password:123456 ...
-
《vue.js快跑》总结:为什么选择VUE
2019-3-31 为什么选择Vue 有这个一个需求,我们需要根据后端数据接口请求返回的数组在页面中按列表展示? 传统上我们使用jQuery的Ajax发送http请求,获取数据.判断列表数据是否存在, ...
-
java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderL,spring获取context
今天学习spring项目的时候出现了下面的错误信息: java.lang.ClassNotFoundException: org.springframework.web.context.Context ...
-
SNF快速开发平台MVC-*排序组件
1. *排序功能使用 在一些需要排序优先级的数据进行调整处理,如民族数据,在北方实施的时候汉族比较多,希望把汉族放在第一位.在蒙古实施项目时,蒙古族人最多把蒙古族放在第一选择位. 1.1. ...
-
linux与linux远程桌面
https://blog.csdn.net/m0_37343696/article/details/79252979
-
转 微软发布TX(LINQ To Logs And Traces)
作者 Roopesh Shenoy ,译者 马德奎 发布于 一月 09, 2014 | 微软开源技术公司于近日发布了Tx,这是一个开源项目,可以使用日志/跟踪文件辅助调试,以及创建实时监控和告警系统. ...