简体   繁体   English

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

[英]converting class based component with state to functional component with hooks

I have this componet with state, here when the user is online it increases the count.我有这个带有状态的组件,当用户在线时,它会增加计数。 I want to change it to functional component with hooks, which I have done below我想把它改成带钩子的功能组件,我在下面做了

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>
    );

  }
}

Here is my conversion to functional component with hooks,这是我对带有钩子的功能组件的转换,

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>
  )
}

In the class based component, I have read not to use setState one after another so I used the callback function in this.setState like this在基于类的组件中,我已经阅读了不要一个接一个地使用 setState,所以我像这样使用了 this.setState 中的回调函数

this.setState({
        count: this.state.count + 1
      }, () => {
        this.setState({ isOnline: !this.state.isOnline })
      })

Now, in the functional component I have used setCount and setIsOnline one after another is it good ???现在,在功能组件中,我一个接一个地使用了 setCount 和 setIsOnline 好吗???

const handleClick = () => {
    if (!isOnline) {
      setIsOnline(!isOnline)
      setCount(count + 1)
    } else {
      setIsOnline(!isOnline)
    }

I have read to use useEffect for callbacks, but all I get is infinite loop .我已经读过使用 useEffect 进行回调,但我得到的只是无限循环 Even though both of my components work and give me the desired result .尽管我的两个组件都可以工作并给我想要的结果。 I wanted to know if i must use useEffect for the callback or if my implementation with hooks in functional component is correct???我想知道我是否必须对回调使用 useEffect 或者我在功能组件中使用钩子的实现是否正确???

This implementation is correct, yes we should not set one state after the other because setState works asynchronously but since you are only setting two states so its fine.这个实现是正确的,是的,我们不应该一个接一个地设置状态,因为 setState 是异步工作的,但是因为您只设置了两个状态,所以它很好。
Although you can also keep one state object instead of both separate states ie虽然您也可以保留一个状态对象而不是两个单独的状态,即

const [state, setState] = useState({ count: 1, isOnline: true });

And then you can set both object keys in a single setState, like:然后您可以在单个 setState 中设置两个对象键,例如:

setState(() => ({
  count: 1,
  isOnline: false,
}))

Also in the class based approach you have used a callback but you actually don't need that, you can use single setState for setting both states ie同样在基于类的方法中,您使用了回调,但实际上并不需要它,您可以使用单个 setState 来设置两个状态,即

this.setState(() => ({
  count: this.state.count + 1, 
  isOnline: !this.state.isOnline ,
}))

Another important note:另一个重要说明:

Try to use functional set state as I use in examples above, as it reduces the risk of being caught into React state asynchronous issues.尝试使用我在上面示例中使用的功能设置状态,因为它降低了陷入 React 状态异步问题的风险。

Calling set state one after the other is totally fine and is the correct thing to do here:一个接一个地调用 set state 完全没问题,这里是正确的做法:

const handleClick = () => {
  if (!isOnline) {
    setIsOnline(!isOnline)
    setCount(count + 1)
  } else {
    setIsOnline(!isOnline)
  }
}

State is updated asychronously, which means that your state variables isOnline and count don't actually change until your component re-renders.状态是异步更新的,这意味着您的状态变量isOnlinecount在您的组件重新呈现之前实际上不会改变。 Calling setCount and setIsOnline doesn't update these variables, but tells React to update on the next render.调用setCountsetIsOnline不会更新这些变量,而是告诉 React 在下一次渲染时更新。

This is why you can't do something like this:这就是为什么你不能做这样的事情:

const handleClick = () => {
    setCount(count + 1)
    setCount(count + 1)
}

The count would be incremented by 1, NOT by 2.计数将增加 1,而不是 2。

Why?为什么?

Because the value count has not been updated yet, since we have to wait until re-render before it gets updated.因为值count还没有更新,因为我们必须等到重新渲染才能更新。 That means count has the same value the entire way through the function - it never changes.这意味着count在整个函数中具有相同的值 - 它永远不会改变。 So you can call setCount(count + 1) a million times and the value will only ever increment by 1.因此,您可以调用setCount(count + 1)一百万次,并且该值只会增加 1。

This is what people mean when they say you should use the set state callback function.这就是人们说你应该使用 set state 回调函数时的意思。

This is the set state callback function:这是设置状态回调函数:

const handleClick = () => {
    setCount(prev => prev + 1)
    setCount(prev => prev + 1)
}

This works as expected, and count will now be incremented by 2.这按预期工作, count现在将增加 2。

If we pass a function like this prev => prev + 1 to set state, React will pass the most recent value to the function.如果我们传递一个像prev => prev + 1这样的函数来设置状态,React 会将最近的值传递给该函数。

The rule is:规则是:

Every time you use the old state value to set the new state value - pass a function to set state.每次使用旧状态值来设置新状态值时 - 传递一个函数来设置状态。

So although your current implementation does work, you should really be passing a function to set state on count since you are depending on previous state:因此,尽管您当前的实现确实有效,但您确实应该传递一个函数来设置count状态,因为您依赖于先前的状态:

const handleClick = () => {
  if (!isOnline) {
    setIsOnline(!isOnline)
    setCount(prev => prev + 1)
  } else {
    setIsOnline(!isOnline)
  }
}

Usually you should do this for your boolean value too, for example:通常,您也应该为布尔值执行此操作,例如:

setIsOnline(prev => !prev)

but since you're using isOnline in your if statement, you shouldn't do that here as the prev value may be different than the value your if uses.但是由于您在 if 语句中使用isOnline ,您不应该在这里这样做,因为prev值可能与if使用的值不同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM