Skip to content

Instantly share code, notes, and snippets.

@yarastqt
Last active March 4, 2020 12:19
Show Gist options
  • Save yarastqt/2140392fd9f6d2297581fc03cc07c8ba to your computer and use it in GitHub Desktop.
Save yarastqt/2140392fd9f6d2297581fc03cc07c8ba to your computer and use it in GitHub Desktop.

React Classes-Component vs Functional-Component

Компоненты собственно бывают двух типов

Для начала возьмем компонент написанный на классе:

class SmartComponent extends Componennt {
  static defaultProps = {
    page: 1,
  }
  
  constructor(props) {
    super(props)
    this.state = {
      data: [],
      loading: true,
    }
  }

  componentDidMount() {
    this.fetchData()
  }

  componentDidUpdate(prevProps) {
    if (this.props.page !== prevProps.page) {
      this.fetchData()
    }
  }

  fetchData() {
    api.fetchData(this.props.page)
      .then(data => {
        this.setState({ data, loading: false })
      })
  }

  render() {
    if (this.state.loading) {
      return <div>Loading...</div>
    }

    return (
      <div>
        {this.state.data.map(value => (
          <div>{value}</div>
        ))}
      </div>
    )
  }
}

и перепишем его на функциональный компонент, что нам для этого нужно?

  1. Указать, что есть дефолтное свойство для page.
  2. Создать два стейта для data и loading.
  3. Вызвать фетч данных при маунте и при обновлении.

И так, чтобы создать локальный стейт необходимо воспользоваться функцией useState, она в качестве аргумента принимает собственно первоначальное состояние (так же хочется сказать, что не стоит запихивать в useState весь шейп стейта, лучше сделать несколько отдельных стейтов) и возввращает тапл, где первый элемент является стейт, а второй элемент является диспатчером, который этот стейт обновлят:

Плохой пример:

// Так делать плохо, т.к. нужно будет копировать шейп и изменять только нужное состояние:
const [state, setState] = useState({ data: [], loading: true })
setState({ ...state, loading: false })

Хороший пример:

// Так делать хорошо, т.к. мы обновляем нужный нам кусок стейта
const [data, setData] = useState([])
const [loading, setLoading] = useState(false)
setData([])
setLoading(false)

Далее, чтобы реагировать на какое-то изменение в нашем вью мы будем использовать useEffect, он принимает два аргумента, первый это колбек которйы будет вызван и второй это набор зависимых свойств при изменении которых будет вызван колбек.

Пример как реагировать при изменении конкретно свойства:

// Колбек будет вызван первый раз при маунте и в последующий раз когда изменится page
useEffect(() => {
  ...
}, [page])

Пример как реагировать при изменении любого свойства:

// В качестве второго аргумента не передаем массив, это означает то, что нужно вызывать колбек всегда
useEffect(() => {
  ...
})

Пример как реагировать только при маунте:

// В качестве второго аргумента передаем пустой массив, в итоге выполнится один раз при маунте
useEffect(() => {
  ...
}, [])

И так, приступаем к написанию компонента:

const SmartComponent = ({ page = 1 }) => {
  const [data, setData] = useState([])
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    api.fetchData(page)
      .then(data => {
        setData(data)
        setLoading(false)
      })
    // Тут нам уже не надо проверять прошлый page и текущий, т.к. эта логика инкапсулирована внутри.
  }, [page])
  
  if (loading) {
    return <div>Loading...</div>
  }

  return (
    <div>
      {data.map(value => (
        <div>{value}</div>
      ))}
    </div>
  )
}

Как мы видим, теперь нам не нужно повторно вызывать фетчинг данных в маунте и апдейте, у нас происходит это все в одном месте, useEffect вносит немного другую парадигму о том, как нужно проектировать компонент.

В итоге мы проектируем так, как выглядил бы компонент в каждый момент времени.

@YanLobat
Copy link

YanLobat commented Mar 4, 2020

а вместо useEffect можно вообще гейт и вынести логику из компонента 🤣

@yarastqt
Copy link
Author

yarastqt commented Mar 4, 2020

Я писал этот md в качестве примера для коллеги, тут речь не про бизнец логику шла :)

@YanLobat
Copy link

YanLobat commented Mar 4, 2020

понимаю, я так с другого гиста мимо пробегал прост :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment