我对此状态有状态,当用户在线时,它会增加计数。我想将其更改为带有钩子的功能组件,这已在下面完成
class App extends React.Component {
state = {
isOnline: true,
count: 1
}
handleOnline = () => {
if (!this.state.isOnline) {
this.setState({
count: this.state.count + 1
}, () => {
this.setState({ isOnline: !this.state.isOnline })
})
} else {
this.setState({ isOnline: !this.state.isOnline })
}
}
render() {
return (
<div className="App">
<h1>online ==> {this.state.isOnline ? 'Online' : 'Offline'}</h1>
<h1>count ==> {this.state.count}</h1>
<button onClick={this.handleOnline}>Toggle</button>
</div>
);
}
}
这是我转换为带有钩子的功能组件,
const App = () => {
const [isOnline, setIsOnline] = useState(true)
const [count, setCount] = useState(1)
const handleClick = () => {
if (!isOnline) {
setIsOnline(!isOnline)
setCount(count + 1)
} else {
setIsOnline(!isOnline)
}
}
return (
<div className="App">
<h1>online ==> {isOnline ? 'Online' : 'Offline'}</h1>
< h1 > count ==> {count}</h1>
<button onClick={handleClick}>Toggle</button>
</div>
)
}
在基于类的组件中,我读到不要一个接一个地使用setState,因此我像这样在this.setState中使用了回调函数
this.setState({
count: this.state.count + 1
}, () => {
this.setState({ isOnline: !this.state.isOnline })
})
现在,在功能组件中,我一个接一个地使用setCount和setIsOnline很好吗?
const handleClick = () => {
if (!isOnline) {
setIsOnline(!isOnline)
setCount(count + 1)
} else {
setIsOnline(!isOnline)
}
我已经阅读过将useEffect用于回调,但是我得到的只是无限循环。即使我的两个组件都能正常工作,也能达到预期的效果。我想知道我是否必须对回调使用useEffect,或者我在功能组件中带有钩子的实现是否正确??
答案 0 :(得分:1)
此实现是正确的,是的,我们不应该将一个状态设置为另一个状态,因为setState异步工作,但是由于您只设置了两个状态,所以就可以了。
尽管您还可以保留一个状态对象,而不是保留两个单独的状态,即
const [state, setState] = useState({ count: 1, isOnline: true });
然后您可以在单个setState中设置两个对象键,例如:
setState(() => ({
count: 1,
isOnline: false,
}))
同样在基于类的方法中,您使用了回调,但实际上并不需要,您可以使用单个setState来设置两个状态,即
this.setState(() => ({
count: this.state.count + 1,
isOnline: !this.state.isOnline ,
}))
另一个重要说明:
尝试使用我在上面的示例中使用的功能集状态,因为它减少了陷入React状态异步问题的风险。
答案 1 :(得分:0)
一个接一个地调用设置状态是完全可以的,这是正确的做法:
const handleClick = () => {
if (!isOnline) {
setIsOnline(!isOnline)
setCount(count + 1)
} else {
setIsOnline(!isOnline)
}
}
状态会异步更新,这意味着状态变量isOnline
和count
实际上不会更改,直到组件重新渲染为止。调用setCount
和setIsOnline
不会更新这些变量,但是会告诉React在下一个渲染器上进行更新。
这就是为什么你不能做这样的事情:
const handleClick = () => {
setCount(count + 1)
setCount(count + 1)
}
计数将增加1,而不是2。
为什么?
因为值count
尚未更新,因为我们必须等到重新渲染后才能对其进行更新。这意味着count
在整个函数中具有相同的值-它永远不会改变。因此,您可以调用setCount(count + 1)
一百万次,并且该值只会增加1。
这就是人们说您应该使用set state回调函数的意思。
这是设置状态回调函数:
const handleClick = () => {
setCount(prev => prev + 1)
setCount(prev => prev + 1)
}
这可以按预期工作,并且count
现在将增加2。
如果我们传递类似prev => prev + 1
的函数来设置状态,React会将最新值传递给该函数。
规则是:
每次使用旧状态值设置新状态值时,都要传递一个函数来设置状态。
因此,尽管您当前的实现确实可行,但实际上您应该传递一个函数来设置count
上的状态,因为您依赖于先前的状态:
const handleClick = () => {
if (!isOnline) {
setIsOnline(!isOnline)
setCount(prev => prev + 1)
} else {
setIsOnline(!isOnline)
}
}
通常,您也应该为布尔值执行此操作,例如:
setIsOnline(prev => !prev)
但是由于您在if语句中使用isOnline
,因此您不应该在此进行操作,因为prev
的值可能与if
使用的值不同。