преобразование компонента на основе класса с состоянием в функциональный компонент с помощью хуков - PullRequest
0 голосов
/ 06 февраля 2020

У меня есть этот комп onet с состоянием, здесь, когда пользователь онлайн, это увеличивает счет. Я хочу изменить его на функциональный компонент с крючками, что я сделал ниже

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 для обратных вызовов, но все, что я получаю, это бесконечно l oop. Хотя оба моих компонента работают и дают мне желаемый результат. Я хотел знать, должен ли я использовать useEffect для обратного вызова или моя реализация с хуками в функциональном компоненте верна ???

Ответы [ 2 ]

1 голос
/ 06 февраля 2020

Эта реализация верна, да, мы не должны устанавливать одно состояние за другим, потому что 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.

0 голосов
/ 06 февраля 2020

Вызов состояния набора один за другим полностью в порядке, и здесь все правильно:

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

Состояние обновляется асинхронно, что означает, что ваши переменные состояния isOnline и count don на самом деле не меняется, пока ваш компонент не рендерится. Вызов setCount и setIsOnline не обновляет эти переменные, но говорит React обновить при следующем рендере.

Вот почему вы не можете сделать что-то подобное:

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

Счет будет увеличен на 1, а НЕ на 2.

Почему?

Поскольку значение count еще не обновлено, так как мы должны подождать до повторной визуализации, прежде чем это обновляется. Это означает, что count имеет одно и то же значение на протяжении всего пути через функцию - оно никогда не меняется. Таким образом, вы можете вызывать setCount(count + 1) миллион раз, и значение будет увеличиваться только на 1.

Это то, что люди имеют в виду, когда говорят, что вы должны использовать функцию обратного вызова установленного состояния.

Это является функцией обратного вызова установленного состояния:

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)

, но так как вы используете isOnline в своем операторе if, вы не должны делать что здесь значение prev может отличаться от v alue ваш if использует.

...