一、收集表单元素
1、基本介绍
-
使用受控组件:表单元素的值由 React 状态管理,需要 onChange 事件来更新状态
-
使用非受控组件:表单元素的值由 DOM 管理,不需要 onChange 事件来更新状态
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 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>
- 使用非受控组件
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、基本介绍
-
高阶函数:如果一个函数符合下面 2 个规范中的任何一个,那该函数就是高阶函数
-
若 A 函数,接收的参数是一个函数,那么 A 函数就可以称之为高阶函数
-
若 A 函数,调用的返回值依然是一个函数,那么 A 函数就可以称之为高阶函数
- 常见的高阶函数有:Promise、setTimeout()、arr.map()
-
-
函数柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式
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 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>
- 不使用函数柯里化
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、基本介绍
-
初始化阶段:由 ReactDOM.render() 触发初次渲染
-
constructor()
-
componentwillMount()
-
render():必须使用
-
componentDidMount():常用,一般在这个钩子中做一些初始化的事,例如:发送网络请求、开启定时器、订阅消息
-
-
更新阶段:由组件内部 this.setsate() 或父组件重新 render() 触发
-
shouldComponentUpdate()
-
componentWillUpdate()
-
render()
-
componentDidUpdate()
-
-
卸载组件:由 ReactDOM.unmountComponentAtNode() 触发
- 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>
-
打开页面,输出结果如下
Count: constructor
Count: componentWillMount
Count: render
Count: componentDidMount -
点击 【点我 + 1】 按钮,输出结果如下
Count: shouldComponentUpdate
Count: componentWillUpdate
Count: render
Count: componentDidUpdate -
点击 【不更改任何状态中的数据,强制更新一下】,输出结果如下
Count: componentWillUpdate
Count: render
Count: componentDidUpdate -
点击 【卸载组件】 按钮,输出结果如下
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>
-
打开页面,输出结果如下
A: render
B: render -
点击 【换车】 按钮,输出结果如下
A: render
B: componentWillReceiveProps {carName: '奥拓'}
B: shouldComponentUpdate
B: componentWillUpdate
B: render
B: componentDidUpdate
四、生命周期(新)
1、基本介绍
-
初始化阶段:由 ReactDOM.render() 触发初次渲染
-
constructor()
-
getDerivedStateFromProps()
-
render():必须使用
-
componentDidMount():常用,一般在这个钩子中做一些初始化的事,例如:发送网络请求、开启定
-
-
更新阶段:由组件内部 this.setsate() 或父组件重新 render() 触发
-
getDerivedStateFromProps()
-
shouldComponentUpdate()
-
render()
-
getSnapshotBeforeUpdate()
-
componentDidUpdate()
-
-
卸载组件:由 ReactDOM.unmountComponentAtNode() 触发
- 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>
-
打开页面,输出结果如下
Count: constructor
Count: getDerivedStateFromProps {name: 'tom'} {count: 0}
Count: render
Count: componentDidMount -
点击 【点我 + 1】 按钮,输出结果如下
Count: getDerivedStateFromProps {name: 'tom'} {count: 1}
Count: shouldComponentUpdate
Count: render
Count: getSnapshotBeforeUpdate
Count: componentDidUpdate {name: 'tom'} {count: 0} hello -
点击 【不更改任何状态中的数据,强制更新一下】,输出结果如下
Count: getDerivedStateFromProps {name: 'tom'} {count: 1}
Count: render
Count: getSnapshotBeforeUpdate
Count: componentDidUpdate {name: 'tom'} {count: 1} hello -
点击 【卸载组件】 按钮,输出结果如下
Count: componentWillUnmount