4、React 之 收集表单数据 与 组件生命周期(1)

一、收集表单数据

1、效果

需求:定义一个包含表单的组件
输入用户名密码后,点击登录 提示输入信息

代码示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="test"></div>
</body>
<!-- react 核心库 -->
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<!-- react-dom ,用于支持 react 操作 DOM -->
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<!-- 将 jsx 转化成 js -->
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
//1、创建组件
 class Login extends React.Component{
	 handleSubmit=(event)=>{
	 	event.preventDefault();
	 	const {username,password} = this;
	 	alert(`你数据的用户名是:${username.value},你输入的密码是:${password.value}`)
	 }
	render(){
		return (
			<form action='http://www.learning.com' onSubmit={this.handleSubmit}>
				用户名: <input ref={c=>this.username=c} type='text' name='username'>
				密码: <input ref={c=>this.password=c} type='password' name='password'>
				<button>按钮</button>
			</form>
		)
	}
}
//form 表单默认是 get 请求,parameter 传参。
//2、渲染虚拟DOM到页面
ReactDOM.render(<Login/>, document.getElementById('test'));//第一个参数是 虚拟DOM,第二个参数是 容器。

</script>
</html>

2、理解

包含表单的组件分类:

2.1 受控组件

页面中所有输入类的dom,比如说 input 框,这种输入类的dom ,随着你的输入,就能把输入的东西 维护到状态里面,需要使用的时候直接从状态里面取出来,这种组件就属于 受控组件。相当于 vue 中的双向数据绑定。
优势在于 :能够减少 ref 的使用。

受控组件代码示例:

<script type="text/babel">
//1、创建组件
 class Login extends React.Component{
 //初始化状态
 	state ={
 		username:"",//用户名
 		password:""//密码
 	}
	 handleSubmit=(event)=>{
	 	event.preventDefault(); //阻止表单的提交
	 	const {username,password} = this.state;
	 	alert(`你数据的用户名是:${username},你输入的密码是:${password}`)
	 }
	 saveUsername = (event)=>{
	 	this.setState({username:event.target.value})//用户名维护到 状态里
	 }
	 savePassword = (event)=>{
	 	this.setState({password:event.target.value})//密码维护到 状态里
	 }
	render(){
		return (
			<form action='http://www.learning.com' onSubmit={this.handleSubmit}>
				用户名: <input onChange={this.saveUsername} ref={c=>this.username=c} type='text' name='username'>
				密码: <input onChange={this.savePassword } ref={c=>this.password=c} type='password' name='password'>
				<button>按钮</button>
			</form>
		)
	}
}
//form 表单默认是 get 请求,parameter 传参。
//2、渲染虚拟DOM到页面
ReactDOM.render(<Login/>, document.getElementById('test'));//第一个参数是 虚拟DOM,第二个参数是 容器。

</script>
2.2 非受控组件

现用现取。等到使用的时候才会去拿 ref 中的值。 不建议使用,尽量少用 ref,会引起性能问题。

代码示例:

<script type="text/babel">
//1、创建组件
 class Login extends React.Component{
	 handleSubmit=(event)=>{
	 	event.preventDefault();
	 	const {username,password} = this;
	 	alert(`你数据的用户名是:${username.value},你输入的密码是:${password.value}`)
	 }
	render(){
		return (
			<form action='http://www.learning.com' onSubmit={this.handleSubmit}>
				用户名: <input ref={c=>this.username=c} type='text' name='username'>
				密码: <input ref={c=>this.password=c} type='password' name='password'>
				<button>按钮</button>
			</form>
		)
	}
}
//form 表单默认是 get 请求,parameter 传参。
//2、渲染虚拟DOM到页面
ReactDOM.render(<Login/>, document.getElementById('test'));//第一个参数是 虚拟DOM,第二个参数是 容器。

</script>

二、扩展:高阶函数与 函数柯里化

1、高阶函数

定义:如果一个函数符合 下面 2个规范中的任何一个,那该函数就是 高阶函数:
1)若 A 函数,接收的参数是一个 函数,那么A 函数就可以称之为高阶函数;
2)若 A 函数,调用的返回值依然是一个函数,那么A 函数就可以称之为高阶函数;(saveFormData函数符合该条件)
常见的高阶函数:
Promise 、数组的 filter 方法、setTimeout(接收函数参数)、arr.map() 等等;

<script type="text/babel">
//1、创建组件
 class Login extends React.Component{
 //初始化状态
 	state ={
 		username:"",//用户名
 		password:""//密码
 	}
	 handleSubmit=(event)=>{
	 	event.preventDefault(); //阻止表单的提交
	 	const {username,password} = this.state;
	 	alert(`你数据的用户名是:${username},你输入的密码是:${password}`)
	 }
	 // saveFormData 的返回值是一个 函数。 对象中的所有的对象名都是一个 字符串。
	 saveFormData= (dataType)=>{
	 	return (event)=>{ // 必须把 一个函数作为函数的回调交给 react 。这个就是 高阶函数。event 是 react 帮忙维护的事件
	 		this.setState({[dataType]:event.target.value})
	 	}
	 }
	render(){
		return (
			<form action='http://www.learning.com' onSubmit={this.handleSubmit}>
				用户名: <input onChange={this.saveFormData('username')} ref={c=>this.username=c} type='text' name='username'>
				密码: <input onChange={this.saveFormData('password')} ref={c=>this.password=c} type='password' name='password'>
				<button>按钮</button>
			</form>
		)
	}
}
//form 表单默认是 get 请求,parameter 传参。
//2、渲染虚拟DOM到页面
ReactDOM.render(<Login/>, document.getElementById('test'));//第一个参数是 虚拟DOM,第二个参数是 容器。

</script>

上面代码不使用高阶函数实现示例:

<script type="text/babel">
//1、创建组件
 class Login extends React.Component{
 //初始化状态
 	state ={
 		username:"",//用户名
 		password:""//密码
 	}
	 handleSubmit=(event)=>{
	 	event.preventDefault(); //阻止表单的提交
	 	const {username,password} = this.state;
	 	alert(`你数据的用户名是:${username},你输入的密码是:${password}`)
	 }
	 // saveFormData 的返回值是一个 函数。 对象中的所有的对象名都是一个 字符串。
	 saveFormData= (dataType,value)=>{
	 	this.setState({[dataType]:value})
	 }
	render(){
		return (
			<form action='http://www.learning.com' onSubmit={this.handleSubmit}>
				用户名: <input onChange={event=>{this.saveFormData('username',event.target.value)}} ref={c=>this.username=c} type='text' name='username'>
				密码: <input onChange={event=>{this.saveFormData('password',event.target.value)}} ref={c=>this.password=c} type='password' name='password'>
				<button>按钮</button>
			</form>
		)
	}
}
//form 表单默认是 get 请求,parameter 传参。
//2、渲染虚拟DOM到页面
ReactDOM.render(<Login/>, document.getElementById('test'));//第一个参数是 虚拟DOM,第二个参数是 容器。

</script>

补充:对象相关的知识

<scritp>
	 let a = "name"
	 let obj = {} //{name:Tom}
	 obj[a] = "Tom"
	 console.log(obj)
</scritp>

2、函数柯里化

定义:通过函数连续调用返回函数的方式,实现多次接收参数,最后统一处理的函数编码形式。
代码示例:

<scritp>
	//需求:求三个数的和。
	/*
	//常规写法
	function sum(a,b,c){
		return a+b+c;
	}
	*/
	//函数柯里化的方式
	function sum(a,b,c){
		return (b)=>{
			return (c)=>{
				return a+b+c;
			}
		}
	}
</scritp>

三、组件的生命周期

1、效果

需求:定义组件实现以下功能:
1、让指定的问你本做 显示/隐藏 的渐变动画
2、从完全可知,到彻底消失,耗时2s
3、点击“不活了” 按钮从界面中卸载组件。

生命周期回调函数《》生命周期钩子函数 《
状态中的数据可以驱动视图的变化。
代码示例:

<script type="text/babel">
//1、创建组件

 class Life extends React.Component{
 	state={
 		opacity:1
 	}
 	componentDidMount(){ //render 的兄弟,只调用一次。组件挂载完毕
 		this.timer = setInterval(()=>{
	 		let {opacity} = this.state;
	 		opacity -= 0.1 //设置透明度
	 		if(opacity <= 0){
	 			opacity  = 1;
	 		}
	 		this.setState({opacity})
	 	},200)
 	} 
 	//组件将要被卸载的时候调用
 	componentWillUnmount(){
 		//清除定时器
 		clearInterval(this.timer);
 	}
 	death = ()=>{
 		
 		//卸载组件。 ReactDOM.unmountComponentAtNode();
 		ReactDOM.unmountComponentAtNode(document.getElementById("test));
 	}
 	render(){//render 调用次数 1(初始化)+n (state中的数据变化) 
 		return {
 			<div>
 				<h2 style={{opacity:this.state.opacity}}>React 学不会,怎么办?</h2>
 				<button onClick={this.death}>不活了</button>
 			</div>
 		}
 	}
}
//form 表单默认是 get 请求,parameter 传参。
//2、渲染虚拟DOM到页面
ReactDOM.render(<Life />, document.getElementById('test'));//第一个参数是 虚拟DOM,第二个参数是 容器。

</script>

挂载:mount
卸载:unmount

2、理解

1)组件从创建到死亡会经历的一些特定的阶段;
2)React 组件中包含一系列钩子函数(生命周期回调函数),会在特定的时刻调用;
3)我们在定义组件时,会在特定的生命周期函数中,做特定的工作。

3、生命周期流程图(旧)

4、React 之 收集表单数据 与 组件生命周期(1)_第1张图片
代码示例:
点击按钮后+1;

挂载时的流程代码示例:
4、React 之 收集表单数据 与 组件生命周期(1)_第2张图片

<script type="text/babel">
//1、创建组件

 class Count extends React.Component{
	 //构造器 ---- 初始化
	 constructor(props){
	 	console.log("Count --- constructor); //第 1 步打印
	 	super(props);
	 	//初始化状态
	 	this.state={ count:0 };
	 }
 	
 	add=()=>{
 		let {count} = this.state;//获取原状态
 		this.setState({count:count+1})
 	}
 	//组件将要挂载的 钩子
 	componentWillMount(){
 		console.log("Count --- componentWillMount") //第 2 步打印
 	}
 	//组件挂载完毕的钩子
 	componentDidMount(){
 		console.log("Count --- componentDidMount") //第 4 步打印
 	}
 	render(){//render 调用次数 1(初始化)+n (state中的数据变化)
 		console.log("Count---render") //第 3 步打印
 		let {count} = this.state;
 		return {
 			<h2>当前求和为:{count}</h2>
 			<button onClick={this.add}>点我+1</button>
 		}
 	}
}

//2、渲染虚拟DOM到页面
ReactDOM.render(<Count/>, document.getElementById('test'));//第一个参数是 虚拟DOM,第二个参数是 容器。

</script>

代码示例2:
组件流程
4、React 之 收集表单数据 与 组件生命周期(1)_第3张图片

<script type="text/babel">
//1、创建组件

 class Count extends React.Component{
	 //构造器 ---- 初始化
	 constructor(props){
	 	console.log("Count --- constructor); //第 1 步打印
	 	super(props);
	 	//初始化状态
	 	this.state={ count:0 };
	 }
 	
 	add=()=>{
 		let {count} = this.state;//获取原状态
 		this.setState({count:count+1})
 	}
 	//卸载组件按钮的回调
 	death=()=>{
 		ReactDOM.unmountComponentAtNode(document.getElementById("test"));
 	}
 	//组件将要卸载
 	componentWillUnmount(){
 		console.log("Count --- componentWillUnmount") //按钮点击卸载打印
 	}
 	//组件将要挂载的 钩子
 	componentWillMount(){
 		console.log("Count --- componentWillMount") //第 2 步打印
 	}
 	//组件挂载完毕的钩子
 	componentDidMount(){
 		console.log("Count --- componentDidMount") //第 4 步打印
 	}
 	//控制组件更新的"阀门",返回为 true 则继续往下,返回 false 则不更新页面。后续流程暂停
 	//调用了 setState 方法后就会到这个钩子,是否更新组件。不写钩子函数,底层会自动添加一个,并且具有一个默认返回值:true。
 	//写了这个钩子函数,就必须要写返回值,否则默认为 undefined,会报警告或者报错。
 	shouldComponentUpdate(){
 		console.log("Count --- shouldComponentUpdate");
 		return true;
 	}
 	//组件将要更新的钩子
 	componentWillUpdate(){
 		console.log("Count --- componentWillUpdate");
 	}
 	//组件更新完毕的钩子
 	componentDidUpdate(){
 		console.log("Count --- componentDidUpdate");
 	}
 	render(){//render 调用次数 1(初始化)+n (state中的数据变化)
 		console.log("Count---render") //第 3 步打印
 		let {count} = this.state;
 		return {
 			<h2>当前求和为:{count}</h2>
 			<button onClick={this.add}>点我+1</button>
 			<button onClick={this.death}>卸载组件</button>
 		}
 	}
}

//2、渲染虚拟DOM到页面
ReactDOM.render(<Count/>, document.getElementById('test'));//第一个参数是 虚拟DOM,第二个参数是 容器。

</script>

代码示例3:
组件流程
4、React 之 收集表单数据 与 组件生命周期(1)_第4张图片

<script type="text/babel">
//1、创建组件

 class Count extends React.Component{
	 //构造器 ---- 初始化
	 constructor(props){
	 	console.log("Count --- constructor); //第 1 步打印
	 	super(props);
	 	//初始化状态
	 	this.state={ count:0 };
	 }
 	
 	add=()=>{
 		let {count} = this.state;//获取原状态
 		this.setState({count:count+1})
 	}
 	//卸载组件按钮的回调
 	death=()=>{
 		ReactDOM.unmountComponentAtNode(document.getElementById("test"));
 	}
 	//强制更新按钮的回调
 	force= () => {
 		this.forceUpdate();
 	}
 	//组件将要卸载
 	componentWillUnmount(){
 		console.log("Count --- componentWillUnmount") //按钮点击卸载打印
 	}
 	//组件将要挂载的 钩子
 	componentWillMount(){
 		console.log("Count --- componentWillMount") //第 2 步打印
 	}
 	//组件挂载完毕的钩子
 	componentDidMount(){
 		console.log("Count --- componentDidMount") //第 4 步打印
 	}
 	//控制组件更新的"阀门",返回为 true 则继续往下,返回 false 则不更新页面。后续流程暂停
 	//调用了 setState 方法后就会到这个钩子,是否更新组件。不写钩子函数,底层会自动添加一个,并且具有一个默认返回值:true。
 	//写了这个钩子函数,就必须要写返回值,否则默认为 undefined,会报警告或者报错。
 	shouldComponentUpdate(){
 		console.log("Count --- shouldComponentUpdate");
 		return true;
 	}
 	//组件将要更新的钩子
 	componentWillUpdate(){
 		console.log("Count --- componentWillUpdate");
 	}
 	//组件更新完毕的钩子
 	componentDidUpdate(){
 		console.log("Count --- componentDidUpdate");
 	}
 	render(){//render 调用次数 1(初始化)+n (state中的数据变化)
 		console.log("Count---render") //第 3 步打印
 		let {count} = this.state;
 		return {
 			<h2>当前求和为:{count}</h2>
 			<button onClick={this.add}>点我+1</button>
 			<button onClick={this.death}>卸载组件</button>
 			<button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
 		}
 	}
}

//2、渲染虚拟DOM到页面
ReactDOM.render(<Count/>, document.getElementById('test'));//第一个参数是 虚拟DOM,第二个参数是 容器。

</script>

代码示例4:
组件流程
4、React 之 收集表单数据 与 组件生命周期(1)_第5张图片

<script type="text/babel">
//1、创建组件

 class Count extends React.Component{
	 //构造器 ---- 初始化
	 constructor(props){
	 	console.log("Count --- constructor); //第 1 步打印
	 	super(props);
	 	//初始化状态
	 	this.state={ count:0 };
	 }
 	
 	add=()=>{
 		let {count} = this.state;//获取原状态
 		this.setState({count:count+1})
 	}
 	//卸载组件按钮的回调
 	death=()=>{
 		ReactDOM.unmountComponentAtNode(document.getElementById("test"));
 	}
 	//强制更新按钮的回调
 	force= () => {
 		this.forceUpdate();
 	}
 	//组件将要卸载
 	componentWillUnmount(){
 		console.log("Count --- componentWillUnmount") //按钮点击卸载打印
 	}
 	//组件将要挂载的 钩子
 	componentWillMount(){
 		console.log("Count --- componentWillMount") //第 2 步打印
 	}
 	//组件挂载完毕的钩子
 	componentDidMount(){
 		console.log("Count --- componentDidMount") //第 4 步打印
 	}
 	//控制组件更新的"阀门",返回为 true 则继续往下,返回 false 则不更新页面。后续流程暂停
 	//调用了 setState 方法后就会到这个钩子,是否更新组件。不写钩子函数,底层会自动添加一个,并且具有一个默认返回值:true。
 	//写了这个钩子函数,就必须要写返回值,否则默认为 undefined,会报警告或者报错。
 	shouldComponentUpdate(){
 		console.log("Count --- shouldComponentUpdate");
 		return true;
 	}
 	//组件将要更新的钩子
 	componentWillUpdate(){
 		console.log("Count --- componentWillUpdate");
 	}
 	//组件更新完毕的钩子
 	componentDidUpdate(){
 		console.log("Count --- componentDidUpdate");
 	}
 	render(){//render 调用次数 1(初始化)+n (state中的数据变化)
 		console.log("Count---render") //第 3 步打印
 		let {count} = this.state;
 		return {
 			<h2>当前求和为:{count}</h2>
 			<button onClick={this.add}>点我+1</button>
 			<button onClick={this.death}>卸载组件</button>
 			<button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
 		}
 	}
}
 class ADom extends React.Component{
 	//初始化状态
 	state={carName:"奔驰"}
 	changeCar = () => {
 		this.setState({carName:"奥拓"})
 	}
 	render(){
 		return {
 			<div>
 				<h2>我是父组件,想要BDom 组件展示信息</h2>
 				<button onClick={this.changeCar}>换车</button>
 				<BDom carName={this.state.carName} />
 			</div>
 		}
 	}
}
 class BDom extends React.Component{
 	//组件将要接收新的 props 的钩子函数
 	//第一次传入的参数不算,第一次以后传的参数才算 props。
 	componentWillReceiveProps(props){
 		console.log("BDom --- componentWillReceiveProps", props)
 	}
 	//控制组件更新的"阀门"
 	shouldComponentUpdate(){
 		console.log("BDom --- shouldComponentUpdate");
 		return true;
 	}
 	//组件将要更新的钩子
 	componentWillUpdate(){
 		console.log("BDom --- componentWillUpdate");
 	}
 	//组件更新完毕的钩子
 	componentDidUpdate(){
 		console.log("BDom --- componentDidUpdate");
 	}
 	render(){
 		console.log("BDom --- render");
 		return {
 			<div>
 				<h2>我是子组件,接收到的车名是:{this.props.carName}</h2>
 			</div>
 		}
 	}
}
//2、渲染虚拟DOM到页面
ReactDOM.render(<ADom />, document.getElementById('test'));//第一个参数是 虚拟DOM,第二个参数是 容器。

</script>
生命周期的三个阶段(旧):
(1)初始化阶段 :由 React DOM.render() 触发 — 初次渲染

1)constructor()
2)componentWillMount()
3)render()
4)componentDidMount() ====>常用,一般在这个钩子中做一些初始化的事情,例如:开启定时器、发送网络请求、订阅消息

(2)更新阶段:由组件内部 this.setState() 或 父组件重新 render 触发

1)shouldComponentUpdate()
2)componentWillUpdate()
3)render() ====>常用
4)componentDidUpdate()

(3)卸载组件:由 React.unmountComponentAtNode() 触发

1)componentWillUnmount() ====>常用,一般在这个钩子中做一些收尾的事情,例如:关闭定时器、取消订阅消息。

4、生命周期流程(新)

4、React 之 收集表单数据 与 组件生命周期(1)_第6张图片

<script type="text/babel">
//1、创建组件

 class Count extends React.Component{
	 //构造器 ---- 初始化
	 constructor(props){
	 	console.log("Count --- constructor); //第 1 步打印
	 	super(props);
	 	//初始化状态
	 	this.state={ count:0 };
	 }
 	
 	add=()=>{
 		let {count} = this.state;//获取原状态
 		this.setState({count:count+1})
 	}
 	//卸载组件按钮的回调
 	death=()=>{
 		ReactDOM.unmountComponentAtNode(document.getElementById("test"));
 	}
 	//强制更新按钮的回调
 	force= () => {
 		this.forceUpdate();
 	}
 	//必须要有返回值。返回 null 或者 状态对象(状态中的东西)
 	// 利用返回值能够指定状态。影响状态的更新。
 	// 接收到一个 props ,得到一个 对象,这种就是派生.
 	//state 的值在任何时候都取决于 props
 	// 如果 state 的值在任何时候都取决于 props,那么可以使用 getDerivedStateFromProps
 	static getDerivedStateFromProps(props){
 		console.log("getDerivedStateFromProps",props);
 		return null;
 		//return props;
 	}
 	// 在更新之前获取快照
 	// 传递快照值,快照值可以是任何类型,比如字符串、数字等
 	getSnapshotBeforeUpdate(){
 		console.log("getSnapshotBeforeUpdate");
 		return null;
 	}
 	//组件将要卸载
 	componentWillUnmount(){
 		console.log("Count --- componentWillUnmount") //按钮点击卸载打印
 	}
 	//组件将要挂载的 钩子
 	componentWillMount(){
 		console.log("Count --- componentWillMount") //第 2 步打印
 	}
 	//组件挂载完毕的钩子
 	componentDidMount(){
 		console.log("Count --- componentDidMount") //第 4 步打印
 	}
 	//控制组件更新的"阀门",返回为 true 则继续往下,返回 false 则不更新页面。后续流程暂停
 	//调用了 setState 方法后就会到这个钩子,是否更新组件。不写钩子函数,底层会自动添加一个,并且具有一个默认返回值:true。
 	//写了这个钩子函数,就必须要写返回值,否则默认为 undefined,会报警告或者报错。
 	shouldComponentUpdate(){
 		console.log("Count --- shouldComponentUpdate");
 		return true;
 	}
 	//组件更新完毕的钩子
 	componentDidUpdate(preProps,preState,snapShotValue){
 		console.log("Count --- componentDidUpdate",preProps,preState,snapShotValue);
 	}
 	render(){//render 调用次数 1(初始化)+n (state中的数据变化)
 		console.log("Count---render") //第 3 步打印
 		let {count} = this.state;
 		return {
 			<h2>当前求和为:{count}</h2>
 			<button onClick={this.add}>点我+1</button>
 			<button onClick={this.death}>卸载组件</button>
 			<button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
 		}
 	}
}

//2、渲染虚拟DOM到页面
ReactDOM.render(<Count count={200} />, document.getElementById('test'));//第一个参数是 虚拟DOM,第二个参数是 容器。

</script>
getSnapshotBeforeUpdate 的应用场景

你可能感兴趣的:(React,react.js,javascript,前端)