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

相关推荐
SuperEugene2 小时前
Monorepo + pnpm workspace 落地实操:Vue 中后台多项目 / 组件库 / 公共包管理|Vue 工程化篇
前端·javascript·vue.js·pnpm·vite·monorepo
We་ct2 小时前
JSX & ReactElement 核心解析
前端·react.js·面试·架构·前端框架·reactjs·个人开发
白中白121382 小时前
杂七杂八补充系列
开发语言·前端·javascript
Xingxing?!2 小时前
Vue2 微信小程序:页面间传递数组
前端·vue.js·uni-app
肉肉不吃 肉2 小时前
代理服务的原理,及Vite 中具体实现方法
前端·vue.js
前端小D2 小时前
作用域/闭包
前端·javascript
前端 贾公子2 小时前
@uni-helper 社区:让 uni-app 拥抱 ESM 时代
开发语言·前端·javascript
大卡拉米2 小时前
ClaudeCode安装及使用
前端·学习
无巧不成书02182 小时前
React Native 深度解析:从架构到实战
react native·react.js·架构