zoukankan      html  css  js  c++  java
  • 初识React,Virutal DOM, State以及生命周期

    这是React分类下的第一篇文章,是在了解了一些基本面后,看Tyler文章,边看边理解边写的。


    React可以看做是MVC中的V,关注的是视图层。React的组件就像Angular的Directive,包括了HTML,CSS,JS以及相关数据等。React的组件被定义在了以"JSX"为后缀的文件中,这些JSX文件会被最终编译成Javascript文件。


    来看一个最基本的写法:
    var HelloWorld = React.createClass({
    	render: function(){
    		return (
    			<div>
    				Hello World!
    			</div>
    		)
    	}
    });
    
    ReactDOM.render(<HelloWorld />, document.getElementBy('app'));
    

    以上,我们可以了解到:

    • 组件创建:React.createClass用来创建组件,接收一个object,render字段必须有
    • 组件名称:就像这里的HelloWorld,通常是大写
    • 组件渲染:通过ReactDOM.render来渲染组件,该方法接收2个参数,一个参数代表组件,另一个代表渲染的位置
    • 组件的呈现方式:组件是以类似HTML元素的形式呈现的,另外,如果组件中有变量,变量会以类似HTML元素属性的形式呈现
    • JSX:以上的的<div>Hello World!</div>和通常的HTML代码不一样,是放在以jsx为后缀的文件中的,最终会被转换成一个Javascript对象,最终React会创建一个"virtual DOM",React会通过React.createElement("div", null, "Hello Wolrd")创建虚拟的DOM。

    1、React在"virtual DOM"这部分是如何工作的?


    → 检查数据发生变化的部分
    → 重新渲染virutal DOM
    → 与上一次的virtual DOM进行比较
    → 在实际DOM上只更新发生变化的部分


    2、State


    var HelloUser = React.createClass({
    	getInitialState: function(){
    		return {
    			username: 'firstusername'
    		}
    	},
    	render: function(){
    		return (
    			<div>
    				Hello {this.state.username}
    			</div>
    		)
    	}
    });
    
    • 设置组件初始状态:通过getInitialState方法返回object对象,为state中的字段赋值
    • 获取组件状态:通过this.state.字段名来获取字段状态
    • 设置组件状态:setState虽然在上面没有提及,但这个方法时被用来真正设置组件状态的。而且这个setState方法是最常用的,当页面有数据变化,Reacct会触发setState方法,渲染virtual DOM,与上一次的virtual DOM进行比较,最后更新发生变化的部分。

    2.1 通过事件改变状态


    以上,是通过getInitialState方法设置了一个初始状态,如何通过事件来触发改变状态呢?比如有一个<input>,通过它的onChange方法来触发改变状态。


    var HelloUser = React.creatClass({
    	getInitialState: function(){
    		return {
    			username: 'darren'
    		}
    	},
    	handleChange: function(e){
    		this.setState({
    			usename: e.target.value
    		});
    	},
    	render: function(){
    		return (
    			<div>
    				Hello {this.state.username}<br/>
    				Change Name:<input type="text" value={this.state.username} onChange={this.handleChange}>
    			</div>
    		)
    	}
    });
    
    • input的onChange事件交给了this.handleChange
    • handleChange方法中,通过setState改变变量的状态,接着,React渲染一个新的virtual DOM, 与上一次的virtual DOM比较差异,最后只更新发生变化的那部分DOM
    • React的onChange方法用来触发事件

    2.2 嵌套组件的状态传递


    现在,我们知道了如何设置组件的初始状态,也知道如何如何设置组件的状态,现在来到另外一个话题:当主键有嵌套的时候,如何把父组件的状态传递给子组件呢?


    先来看没有组件嵌套的情况:

    var HelloUser = React.createClass({
    	render: function(){
    		return (
    			<div> Hello, {this.props.name}</div>
    		)
    	}
    });
    
    ReactDOM.render(<HelloUser name="darren" />, document.getElementById('app'));
    
    • 组件在jsx语法中,是以类似页面元素的形式呈现的,比如这里的<HelloUser />,组件中的变量,比如这里的name字段,在jsx语法中是以属性名存在的,比如这里的<HelloUser name="darren">
    • 对ReactDOM来说,它知道<HelloUser name="darren" />就是需要渲染的组件,HelloUser就是组件的名称,给name赋的值最终赋值给了props属性

    再来看存在组件嵌套的情况下,如何传递State。

    被嵌套的组件:

    var ShowList = React.createClass({
    	render: function(){
    		var listItems = this.props.names.map(function(friend){
    			return <li>{{friend}}</li>;
    		});
    
    		return (
    			<div>
    				<h3>Friends</h3>
    				<ul>
    					{listItems}
    				</ul>
    			</div>
    		)
    	}
    });
    

    以上,ShowList组件的视图渲染需要外界给names字段赋上数组。也就是<ShowList names=... />中names属性需要赋值。从哪里赋值呢?可以从嵌套组件的state中获取。


    好,那就来到嵌套组件:

    var ParentContainer = React.createClass({
    	getIntitialState: function(){
    		return {
    			name: 'darren',
    			friends:['a','bob']
    		}
    	},
    	render: function(){
    		return (
    			<div>
    				<h3>Name: {this.state.name}</h3>
    				<ShowList names={this.state.friends}>
    			</div>
    		)
    	}
    });
    
    • 我们知道getIntitialState中返回对象的各个字段是放在了state中的
    • state中的friends是数组,赋值给了ShowList的names属性
    • 嵌套组件和被嵌套组件之间state的传递看上去像一条河流,嵌套组件是河流的上游,被嵌套组件是下游,河水是单向流动的,上游的state向下游流动,传递给了下流的被嵌套组件

    现在,组件看起来就像C#中对类的封装。React的组件是否和C#中的类有更多的相似性呢?


    假设,在显示朋友列表的页面再增加一块区域,用来添加朋友信息。那,我们有必要为这一块添加的区域定义一个组件:

    var AddFriend = React.createClas({
    	getIntialState: function(){
    		return {
    			newFriend: ''
    		}
    	},
    	updateNewFriend: function(e){//更新就是为state的newFriend字段赋上当前的值
    		this.setState({
    			newFriend: e.target.value
    		});
    	},
    	handleAddNew: function(){
    		this.props.addNew(this.state.newFriend);
    		this.setState({
    			newFriend: ''
    		});
    	},
    	render: function(){
    		return (
    			<div>
    				<input type="text" value={this.state.newFriend} onChange={this.updateNewFriend} />
    				<button onClick={this.handleAddNew}>Add Friend</button>
    			</div>
    		)
    	}
    });
    
    • input文本框的值取决于state中的newFriend字段值
    • 为input添加了onChange事件,该事件由updateNewFriend这个代表函数的字段所定义
    • 在updateNewFriend函数中,把文本框的当前值赋值给state中的newFriend字段
    • 为button添加了一个onClick事件,该事件由handleAddNew所代表函数的字段所定义,而在handleAddNew函数内部,props属性需要由外界来赋值。会类似<AddFriend addNew={...} />这样的形式呈现

    以上的AddFriend组件是也是一个被嵌套组件,它和ShowList组件被一起嵌套在ParentContainer这个组件中。


    于是,就来到了ParentContainer这个组件。

    var ParentContainer = React.createClass({
    	getInitialState: function(){
    		return {
    			name: 'darren',
    			friends: ['a','b']
    		}
    	},
    	addFriend: function(friend){
    		this.setState({
    			this.setState({
    				friends: this.state.friends.concat([friend])
    			});
    		});
    	},
    	render: function(){
    		return (
    			<div>
    				<h3>Name: {this.state.name}</h3>
    				<AddFriend addNew={this.addFriend} />
    				<ShowList names={this.state.friends} />
    			</div>
    		)
    	}
    });
    

    被嵌套组件所需要的,都通过嵌套组件的state或函数获得。


    2.3 设置组件的属性类型


    在上面的AddFriend组件中,button是这样的:<button onClick={this.handleAddNew}>Add Friend</button>,button的点击事件由handleAddNew函数决定,而handleAddNew函数由this.props.addNew(this.state.newFriend)所决定,addNew函数是props属性的函数类型字段,是否可以定义呢?答案是可以。


    var AddFriend = React.createClas({
    	getIntialState: function(){
    		return {
    			newFriend: ''
    		}
    	},
    	propTypes: {
    		addNew: React.PropTypes.func.isRequired
    	},
    	updateNewFriend: function(e){//更新就是为state的newFriend字段赋上当前的值
    		this.setState({
    			newFriend: e.target.value
    		});
    	},
    	handleAddNew: function(){
    		this.props.addNew(this.state.newFriend);
    		this.setState({
    			newFriend: ''
    		});
    	},
    	render: function(){
    		return (
    			<div>
    				<input type="text" value={this.state.newFriend} onChange={this.updateNewFriend} />
    				<button onClick={this.handleAddNew}>Add Friend</button>
    			</div>
    		)
    	}
    });
    

    3、组件的生命周期


    组件的生命周期又是怎样的呢?

    var FriendsConainer = React.createClass({
    	getInitialState: function(){
    		alert('getInitialState');
    		return {
    			name: 'darren'
    		}
    	},
    	componentWillMount: function(){},
    	componentDidMount: function(){},
    	componentWillReceiveProps: function(nextProps){},
    	componentWillUnmount: function(){},
    	render: function(){
    		return (
    			<div>
    				Hello, {this.state.name}
    			</div>
    		)
    	}
    });
    
    • componentWillMount:初次渲染之前调用一次
    • componentDidMount:初次渲染之后调用,这时,可以访问virtual DOM了
    • componentWillReceiveProps:初次渲染不被调用,只有当props属性值有变化才调用
    • componentWillUnmount:从virutal DOM分离的时候调用
  • 相关阅读:
    java实现遍历树形菜单方法——设计思路【含源代码】
    java实现动态验证码源代码——接受ajax的jsp
    java实现动态验证码源代码——接受ajax的jsp
    java实现动态验证码源代码——绘制验证码的jsp
    java实现动态验证码源代码——绘制验证码的jsp
    java实现动态验证码源代码——jsp页面
    java实现动态验证码源代码——jsp页面
    struts+hibernate+oracle+easyui实现lazyout组件的简单案例——struts.xml配置详情
    struts+hibernate+oracle+easyui实现lazyout组件的简单案例——struts.xml配置详情
    struts+hibernate+oracle+easyui实现lazyout组件的简单案例——Action的实现类
  • 原文地址:https://www.cnblogs.com/darrenji/p/5502989.html
Copyright © 2011-2022 走看看