将具有状态的基于类的组件转换为带有钩子的功能组件

问题描述 投票:-1回答:2

我有这个状态的伴侣,在此当用户在线时,它会增加计数。我想将其更改为带有挂钩的功能组件,这在下面完成了

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或我在功能组件中带有钩子的实现是否正确???

我有这个状态的伴侣,在此当用户在线时,它会增加计数。我想将其更改为带有钩子的功能组件,这是我在类App扩展的React.Component之下完成的。

这种暗示是正确的,是的,我们不应该将一个状态设置为另一个状态,因为setState是异步工作的,但是由于您只设置了两个状态,所以就可以了。虽然您也可以保留一个状态对象,而不是保留两个单独的状态,即const [state,setState] = useEffect({count:1,isOnline:true});然后,您可以在一个setState中设置两个对象键。
同样在基于类的方法中,您使用了回调,但实际上并不需要,您可以使用单个setState来设置两个状态,即this.setState {count:this.state.count + 1,isOnline:!this.state.isOnline,})

一个接一个地调用设置状态是完全可以的,这是正确的做法:

const handleClick = () => { if (!isOnline) { setIsOnline(!isOnline) setCount(count + 1) } else { setIsOnline(!isOnline) } }
状态是不同步更新的,这意味着状态变量isOnlinecount直到组件重新渲染后才真正改变。调用setCountsetIsOnline不会更新这些变量,但会告诉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的值不同。
javascript reactjs callback components react-hooks
2个回答
0
投票

0
投票
状态是不同步更新的,这意味着状态变量isOnlinecount直到组件重新渲染后才真正改变。调用setCountsetIsOnline不会更新这些变量,但会告诉React在下一个渲染器上进行更新。
© www.soinside.com 2019 - 2024. All rights reserved.