我已经看到了 react v16 中引入的这两个新概念。
据我了解:
useState
setState
与钩子类似,并且useEffect
与生命周期方法类似。
我的理解正确吗?useState
如果不是,和之间的确切区别是useEffect
什么?
我已经看到了 react v16 中引入的这两个新概念。
据我了解:
useState
setState
与钩子类似,并且useEffect
与生命周期方法类似。
我的理解正确吗?useState
如果不是,和之间的确切区别是useEffect
什么?
简而言之,useState
增强useEffect
功能组件以使它们做类可以但功能组件(没有钩子)不能做的事情:
useState
允许功能组件具有state,就像this.state
在类组件中一样。useEffect
允许功能组件在一个 API中拥有生命周期方法(例如componentDidMount
、componentDidUpdate
和)。componentWillUnmount
请参阅以下示例以获取更多说明:
useState
class CounterClass extends React.Component {
constructor(props) {
super(props);
this.state = { count: 1 };
}
render() {
return <div>
<p>Count: {this.state.count}</p>
<button onClick={() => this.setState({
count: this.state.count + 1
})}>Increase</button>
</div>;
}
}
function CounterFunction() {
const [count, setCount] = React.useState(1);
return (
<div>
<p>Count: {count}</p>
<button onClick={() =>
setCount(count + 1)}
>Increase</button>
</div>
);
}
ReactDOM.render(
<div>
<CounterClass />
<CounterFunction />
</div>
, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>
useEffect
class LifecycleClass extends React.Component {
componentDidMount() {
console.log('Mounted');
}
componentWillUnmount() {
console.log('Will unmount');
}
render() {
return <div>Lifecycle Class</div>;
}
}
function LifecycleFunction() {
React.useEffect(() => {
console.log('Mounted');
return () => {
console.log('Will unmount');
};
}, []); // Empty array means to only run once on mount.
return (
<div>Lifecycle Function</div>
);
}
ReactDOM.render(
<div>
<LifecycleClass />
<LifecycleFunction />
</div>
, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>
在官方 React 文档中阅读有关useState和useEffect的更多信息。
useState()
首先,我们有不支持的功能组件state
,换句话说,功能组件是无状态组件。
现在,有了 Hooks,我们有了功能组件,但有状态。它是通过使用useState来实现的。
useEffect()
首先,使用无状态功能组件,我们没有组件生命周期钩子。换句话说,无论何时你想使用组件生命周期钩子,你都应该考虑使用类组件。
现在,我们可以在不使用类 component的情况下使用组件生命周期钩子。它是通过使用useEffect来实现的。换句话说,现在每当我们想使用组件生命周期钩子时,我们已经有两种选择,要么使用类组件,要么使用 Hooks with 。useEffect
更新
useState
和之间的确切区别是useEffect
什么?
简单来说,就是useState
让我们原本是无状态的功能组件变成有状态的。并允许我们的功能组件利用组件生命周期挂钩,这些挂钩在过去仅支持类组件。useEffect
useState
并且useEffect
是 React 16.8+ hooks 生态系统的一部分,旨在为功能组件提供与以前仅可用于基于类的组件(state
/setState
和组件生命周期方法(例如componentDidMount
、componentDidUpdate
和componentWillUnmount
)
useState()
直截了当,它允许您在功能组件中拥有状态访问器。
useEffect()
可以组合componentDidMount
, componentDidUpdate
,componentWillUnmount
但很棘手。
您可以从hooks的官方文档中解读我在这里要讨论的大部分内容。在工作中看到钩子比从文本中推理更容易。
预渲染生命周期事件相当于componentWillReceiveProps
或者getDerivedStateFromProps
也componentWillMount
可以只是我们在返回 JSX(react-node)之前在功能组件中首先做的事情,因为函数本身相当于render(…)
基于类的组件的方法。
我们不需要处理预渲染生命周期事件的钩子。
渲染后的生命周期componentDidMount
事件,等同于componentDidUpdate
和componentDidUnmount
基于类的组件。
我们需要****_useEffect(…)_**
处理这些渲染后生命周期事件** 因为我们无法在主组件函数中编写与这些生命周期事件相关的逻辑,因为这些事件应该在组件函数将 JSX(react-node)返回给react-dom
渲染器.
这意味着,我们可以用钩子做很多事情。如何?
我们知道useEffect(fn, […watchStates])
,接受 2 个参数。
fn
:(必需)useEffect
调用此函数以在每个渲染周期后根据 (2) 参数给出的更改跟踪的值作为副作用运行。该函数fn
可以返回另一个函数,该函数应该在效果函数再次运行或组件卸载之前作为清理运行[…watchValues ]
:(可选)useEffect
此数组中的跟踪值已从上一个渲染周期更改,然后仅fn
调用效果。如果未给出此参数,则效果将在每个渲染周期中运行。如果我们不一起传递 (2) 参数,效果逻辑fn
将在每个渲染周期后被调用。
如果我们通过 (2) 数组传递值,组件需要观察变化,并fn
在变化时调用,这很不言自明。
最棘手的部分是使用空数组[]
作为 (2) 参数,我们可以将副作用逻辑限制为仅在安装阶段执行,因为在随后的渲染周期再次fn
触发后没有变化效果挂钩将观察fn
.
import React, { useState, useEffect } from "react";
export default props => {
console.log("componentWillMount");
console.log("componentWillReceiveProps", props);
const [x, setX] = useState(0);
const [y, setY] = useState(0);
const [moveCount, setMoveCount] = useState(0);
const [cross, setCross] = useState(0);
const mouseMoveHandler = event => {
setX(event.clientX);
setY(event.clientY);
};
useEffect(() => {
console.log("componentDidMount");
document.addEventListener("mousemove", mouseMoveHandler);
return () => {
console.log("componentDidUnmount");
document.removeEventListener("mousemove", mouseMoveHandler);
};
}, []); // empty-array means don't watch for any updates
useEffect(
() => {
// if (componentDidUpdate & (x or y changed))
setMoveCount(moveCount + 1);
},
[x, y]
);
useEffect(() => {
// if componentDidUpdate
if (x === y) {
setCross(x);
}
});
return (
<div>
<p style={{ color: props.color }}>
Your mouse is at {x}, {y} position.
</p>
<p>Your mouse has moved {moveCount} times</p>
<p>
X and Y positions were last equal at {cross}, {cross}
</p>
</div>
);
};
代码片段很简单且不言自明。您可以在CodePen上试用。
需要注意的重要一点是,如果您要在效果内进行状态更改,请确保将内部正在更改的状态从监视数组中排除。
例如,在第二个效果(计算鼠标移动的效果)中,我们只在 x 和 y 更新时触发它,通过[x , y]
作为第二个参数传递,因为