React - 收集表单元素、收集表单元素优化、生命周期(旧)、生命周期(新)

一、收集表单元素

1、基本介绍
  1. 使用受控组件:表单元素的值由 React 状态管理,需要 onChange 事件来更新状态

  2. 使用非受控组件:表单元素的值由 DOM 管理,不需要 onChange 事件来更新状态

2、演示
  1. 使用受控组件
html 复制代码
<!doctype html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>受控组件</title>
    </head>

    <body>
        <div id="test"></div>
    </body>

    <script src="../js/react/react.development.js" type="text/javascript"></script>
    <script src="../js/react/react-dom.development.js" type="text/javascript"></script>
    <script src="../js/react/babel.min.js" type="text/javascript"></script>
    <script type="text/babel">
        class Login extends React.Component {
            state = {
                username: "",
                password: "",
            };

            saveUsername = (event) => {
                this.setState({
                    username: event.target.value,
                });
            };

            savePassword = (event) => {
                this.setState({
                    password: event.target.value,
                });
            };

            handleSubmit = (event) => {
                event.preventDefault(); // 阻止表单提交

                let { username, password } = this.state;
                alert(`你输入的用户名是:${username},你输入的密码是:${password}`);
            };

            render() {
                return (
                    <form action="http://www.mytest.com" onSubmit={this.handleSubmit}>
                        用户名:
                        <input onChange={this.saveUsername} type="text" name="username" />
                        密码:
                        <input onChange={this.savePassword} type="password" name="password" />
                        <button>登录</button>
                    </form>
                );
            }
        }

        ReactDOM.render(<Login />, document.getElementById("test"));
    </script>
</html>
  1. 使用非受控组件
html 复制代码
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>非受控组件</title>
	</head>

	<body>
		<div id="test"></div>
	</body>

	<script src="../js/react/react.development.js" type="text/javascript"></script>
	<script src="../js/react/react-dom.development.js" type="text/javascript"></script>
	<script src="../js/react/babel.min.js" type="text/javascript"></script>
	<script type="text/babel">
		class Login extends React.Component {
			handleSubmit = (event) => {
                event.preventDefault(); // 阻止表单提交

                // 这里现用现取
				const { username, password } = this;
				alert(`你输入的用户名是:${username.value},你输入的密码是:${password.value}`);
			};

			render() {
				return (
					<form action="http://www.mytest.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>
				);
			}
		}

		ReactDOM.render(<Login />, document.getElementById("test"));
	</script>
</html>

二、收集表单元素优化

1、基本介绍
  1. 高阶函数:如果一个函数符合下面 2 个规范中的任何一个,那该函数就是高阶函数

    1. 若 A 函数,接收的参数是一个函数,那么 A 函数就可以称之为高阶函数

    2. 若 A 函数,调用的返回值依然是一个函数,那么 A 函数就可以称之为高阶函数

    • 常见的高阶函数有:Promise、setTimeout()、arr.map()
  2. 函数柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式

2、演示
  1. 使用函数柯里化
html 复制代码
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>高阶函数与函数柯里化</title>
	</head>

	<body>
		<div id="test"></div>
	</body>

	<script src="../js/react/react.development.js" type="text/javascript"></script>
	<script src="../js/react/react-dom.development.js" type="text/javascript"></script>
	<script src="../js/react/babel.min.js" type="text/javascript"></script>
	<script type="text/babel">
		class Login extends React.Component {
			state = {
				username: "",
				password: "",
			};

			saveFormData = (dataType) => {
				return (event) => {
					this.setState({
						[dataType]: event.target.value,
					});
				};
			};

			handleSubmit = (event) => {
				event.preventDefault(); // 阻止表单提交

				let { username, password } = this.state;
				alert(`你输入的用户名是:${username},你输入的密码是:${password}`);
			};

			render() {
				return (
					<form action="http://www.mytest.com" onSubmit={this.handleSubmit}>
						用户名:
						<input onChange={this.saveFormData("username")} type="text" name="username" />
						密码:
						<input onChange={this.saveFormData("password")} type="password" name="password" />
						<button>登录</button>
					</form>
				);
			}
		}

		ReactDOM.render(<Login />, document.getElementById("test"));
	</script>
</html>
  1. 不使用函数柯里化
html 复制代码
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>不使用函数柯里化</title>
	</head>

	<body>
		<div id="test"></div>
	</body>

	<script src="../js/react/react.development.js" type="text/javascript"></script>
	<script src="../js/react/react-dom.development.js" type="text/javascript"></script>
	<script src="../js/react/babel.min.js" type="text/javascript"></script>
	<script type="text/babel">
		class Login extends React.Component {
			state = {
				username: "",
				password: "",
			};

			saveFormData = (dataType, event) => {
				this.setState({
					[dataType]: event.target.value,
				});
			};

			handleSubmit = (event) => {
				event.preventDefault(); // 阻止表单提交

				let { username, password } = this.state;
				alert(`你输入的用户名是:${username},你输入的密码是:${password}`);
			};

			render() {
				return (
					<form action="http://www.mytest.com" onSubmit={this.handleSubmit}>
						用户名:
						<input
							onChange={(event) => {
								this.saveFormData("username", event);
							}}
							type="text"
							name="username"
						/>
						密码:
						<input
							onChange={(event) => {
								this.saveFormData("password", event);
							}}
							type="password"
							name="password"
						/>
						<button>登录</button>
					</form>
				);
			}
		}

		ReactDOM.render(<Login />, document.getElementById("test"));
	</script>
</html>

三、生命周期(旧)

1、基本介绍
  1. 初始化阶段:由 ReactDOM.render() 触发初次渲染

    1. constructor()

    2. componentwillMount()

    3. render():必须使用

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

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

    1. shouldComponentUpdate()

    2. componentWillUpdate()

    3. render()

    4. componentDidUpdate()

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

    1. componentwillUnmount():常用,一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
2、演示
html 复制代码
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>生命周期(旧)</title>
	</head>

	<body>
		<div id="test"></div>
	</body>

	<script src="../js/react/react.development.js" type="text/javascript"></script>
	<script src="../js/react/react-dom.development.js" type="text/javascript"></script>
	<script src="../js/react/babel.min.js" type="text/javascript"></script>
	<script type="text/babel">
		class Count extends React.Component {
			
            // 构造器
			constructor(props) {
				console.log("Count: constructor");
				super(props);

				this.state = {
					count: 0,
				};
			}

			add = () => {
				let { count } = this.state;
				this.setState({
					count: count + 1,
				});
			};

			kill = () => {
				ReactDOM.unmountComponentAtNode(document.getElementById("test"));
			};

			force = () => {
				this.forceUpdate();
			};

			// 组件将要挂载的钩子
			componentWillMount() {
				console.log("Count: componentWillMount");
			}

			// 组件挂载完毕的钩子
			componentDidMount() {
				console.log("Count: componentDidMount");
			}

			// 组件将要卸载的钩子
			componentWillUnmount() {
				console.log("Count: componentWillUnmount");
			}

			// 控制组件更新的阀门
			shouldComponentUpdate() {
				console.log("Count: shouldComponentUpdate");
				return true;
			}

			// 组件将要更新的钩子
			componentWillUpdate() {
				console.log("Count: componentWillUpdate");
			}

			// 组件更新完毕的钩子
			componentDidUpdate() {
				console.log("Count: componentDidUpdate");
			}

			render() {
				console.log("Count: render");
				return (
					<div>
						<h2>当前求和为:{this.state.count}</h2>
						<button onClick={this.add}>点我 + 1</button>
						<br />
						<button onClick={this.kill}>卸载组件</button>
						<br />
						<button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
					</div>
				);
			}
		}

		ReactDOM.render(<Count />, document.getElementById("test"));
	</script>
</html>
  1. 打开页面,输出结果如下

    Count: constructor
    Count: componentWillMount
    Count: render
    Count: componentDidMount

  2. 点击 【点我 + 1】 按钮,输出结果如下

    Count: shouldComponentUpdate
    Count: componentWillUpdate
    Count: render
    Count: componentDidUpdate

  3. 点击 【不更改任何状态中的数据,强制更新一下】,输出结果如下

    Count: componentWillUpdate
    Count: render
    Count: componentDidUpdate

  4. 点击 【卸载组件】 按钮,输出结果如下

    Count: componentWillUnmount

3、父组件更新 props 传递给子组件
html 复制代码
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>生命周期(旧)</title>
	</head>

	<body>
		<div id="test"></div>
	</body>

	<script src="../js/react/react.development.js" type="text/javascript"></script>
	<script src="../js/react/react-dom.development.js" type="text/javascript"></script>
	<script src="../js/react/babel.min.js" type="text/javascript"></script>
	<script type="text/babel">

		// 父组件 A
		class A extends React.Component {
			state = {
				carName: "奔驰",
			};

			changeCar = () => {
				this.setState({
					carName: "奥拓",
				});
			};

			render() {
				console.log("A: render");
				return (
					<div>
						<div>我是 A 组件</div>
						<button onClick={this.changeCar}>换车</button>
						<B carName={this.state.carName} />
					</div>
				);
			}
		}

		// 子组件 B
		class B extends React.Component {
			
			// 组件将要接收新的 props 的钩子
			// 第一次接收 props 不会调用,其实应该改为:componentWillReceiveProps()
			// UNSAFE_componentWillReceiveProps() 是 React 对 componentWillReceiveProps() 的渐进式迁移
			UNSAFE_componentWillReceiveProps(props) {
				console.log("B: componentWillReceiveProps", props);
			}

			shouldComponentUpdate() {
				console.log("B: shouldComponentUpdate");
				return true;
			}

			componentWillUpdate() {
				console.log("B: componentWillUpdate");
			}

			componentDidUpdate() {
				console.log("B: componentDidUpdate");
			}

			render() {
				console.log("B: render");
				return (
					<div>
						<div>我是 B 组件</div>
						<div>接收到的车是:{this.props.carName}</div>
					</div>
				);
			}
		}

		ReactDOM.render(<A />, document.getElementById("test"));
	</script>
</html>
  1. 打开页面,输出结果如下

    A: render
    B: render

  2. 点击 【换车】 按钮,输出结果如下

    A: render
    B: componentWillReceiveProps {carName: '奥拓'}
    B: shouldComponentUpdate
    B: componentWillUpdate
    B: render
    B: componentDidUpdate


四、生命周期(新)

1、基本介绍
  1. 初始化阶段:由 ReactDOM.render() 触发初次渲染

    1. constructor()

    2. getDerivedStateFromProps()

    3. render():必须使用

    4. componentDidMount():常用,一般在这个钩子中做一些初始化的事,例如:发送网络请求、开启定

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

    1. getDerivedStateFromProps()

    2. shouldComponentUpdate()

    3. render()

    4. getSnapshotBeforeUpdate()

    5. componentDidUpdate()

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

    1. componentwillUnmount():常用,一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
2、演示
html 复制代码
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>生命周期(新)</title>
	</head>

	<body>
		<div id="test"></div>
	</body>

	<script src="../js/react17.0/react.development.js" type="text/javascript"></script>
	<script src="../js/react17.0/react-dom.development.js" type="text/javascript"></script>
	<script src="../js/react17.0/babel.min.js" type="text/javascript"></script>
	<script type="text/babel">
		class Count extends React.Component {

			// 构造器
			constructor(props) {
				console.log("Count: constructor");
				super(props);

				this.state = {
					count: 0,
				};
			}

			add = () => {
				let { count } = this.state;
				this.setState({
					count: count + 1,
				});
			};

			kill = () => {
				ReactDOM.unmountComponentAtNode(document.getElementById("test"));
			};

			force = () => {
				this.forceUpdate();
			};

			// 若 state 需要根据 props 的变化来更新
			static getDerivedStateFromProps(props, state) {
				console.log("Count: getDerivedStateFromProps", props, state);
				// return { count: 100 }; // 强制修改 state,无论什么情况,都把 count 设置为 100
				// return props; // 用 props 完全替换 state
				return null; // 返回 null 表示不更新 state
			}

			// 在更新之前获取快照
			getSnapshotBeforeUpdate() {
				console.log("Count: getSnapshotBeforeUpdate");
				return "hello";
			}

			// // 组件将要挂载的钩子
			// UNSAFE_componentWillMount() {
			// 	console.log("Count: componentWillMount");
			// }

			// 组件挂载完毕的钩子
			componentDidMount() {
				console.log("Count: componentDidMount");
			}

			// 组件将要卸载的钩子
			componentWillUnmount() {
				console.log("Count: componentWillUnmount");
			}

			// 控制组件更新的阀门
			shouldComponentUpdate() {
				console.log("Count: shouldComponentUpdate");
				return true;
			}

			// // 组件将要更新的钩子
			// UNSAFE_componentWillUpdate() {
			// 	console.log("Count: componentWillUpdate");
			// }

			// 组件更新完毕的钩子
			componentDidUpdate(preProps, preState, snapshotValue) {
				console.log("Count: componentDidUpdate", preProps, preState, snapshotValue);
			}

			render() {
				console.log("Count: render");
				return (
					<div>
						<h2>当前求和为:{this.state.count}</h2>
						<button onClick={this.add}>点我 + 1</button>
						<br />
						<button onClick={this.kill}>卸载组件</button>
						<br />
						<button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
					</div>
				);
			}
		}

		ReactDOM.render(<Count name="tom" />, document.getElementById("test"));
	</script>
</html>
  1. 打开页面,输出结果如下

    Count: constructor
    Count: getDerivedStateFromProps {name: 'tom'} {count: 0}
    Count: render
    Count: componentDidMount

  2. 点击 【点我 + 1】 按钮,输出结果如下

    Count: getDerivedStateFromProps {name: 'tom'} {count: 1}
    Count: shouldComponentUpdate
    Count: render
    Count: getSnapshotBeforeUpdate
    Count: componentDidUpdate {name: 'tom'} {count: 0} hello

  3. 点击 【不更改任何状态中的数据,强制更新一下】,输出结果如下

    Count: getDerivedStateFromProps {name: 'tom'} {count: 1}
    Count: render
    Count: getSnapshotBeforeUpdate
    Count: componentDidUpdate {name: 'tom'} {count: 1} hello

  4. 点击 【卸载组件】 按钮,输出结果如下

    Count: componentWillUnmount

相关推荐
Amumu1213811 小时前
工程化: webpack介绍和基础用法
前端·javascript·工程化
吴声子夜歌11 小时前
Node.js——Web相关模块
前端·node.js
onebound_noah11 小时前
【实战解析】如何高效获取京东商品详情数据(含多语言SDK接入)
java·前端·数据库
SuperEugene11 小时前
前端组件三层架构:页面/业务/基础组件划分,高内聚低耦合|组件化设计基础篇
前端·javascript·vue.js·架构·前端框架·状态模式
迈巧克力11 小时前
用OpenClaw实现小红书自动发布:从零到一的完整技术方案
前端·人工智能·创业
givemeacar11 小时前
十七:Spring Boot依赖 (2)-- spring-boot-starter-web 依赖详解
前端·spring boot·后端
前端郭德纲11 小时前
JavaScript原生开发与鸿蒙原生开发对比
开发语言·javascript·harmonyos
辻戋11 小时前
从零开始手写mini-webpack
前端·webpack·node.js
cch891811 小时前
PHP vs 易语言:Web开发与桌面编程大对决
开发语言·前端·php
百撕可乐12 小时前
NextJS官网实战02:项目的基础骨架搭建
前端·javascript·react.js