React Hooks изменили способ написания компонентов. Хуки мысленно подтолкнули нас к написанию больше функциональных компонентов, чем классических.

Хотя как только вы начинаете создавать свое приложение с помощью хуков, у вас внезапно появляется 10 различных хуков, и даже если они управляют связанным состоянием, становится трудно управлять ими.

Они начинают казаться беспорядком в старых добрых Функциональных компонентах.

Выглядит несвязанным? Взгляните на этот компонент:

import React from 'react';

const DataTable = ({ movies = []}) => (
  <div>
    {movies.map(({Poster, Title, imdbID, Year}) => (
      <div key={imdbID}>
        <img src={Poster} height="100" alt={Title} />
        <p>
          <a href={`/?t=${imdbID}`}>{Title}</a>
          <br />{Year}
        </p>
      </div>
    ))}
  </div>
)

export default DataTable

Теперь, если бы мы добавили запросы на загрузку данных и построили ссылки на профили, это можно было бы сделать двумя способами:

  1. Добавьте все запросы и функции в один компонент
  2. Создайте компонент-оболочку для
  • Сделайте запрос и создайте ссылки
  • Передайте все необходимые данные и функции как реквизиты

Давайте попробуем увидеть оба пути и то, как наш компьютер развивается в размерах и функциональных возможностях.

Загрузка данных, построение обработчиков событий и разметки в одном компоненте:

import React, { useEffect, useState, useContext } from 'react';
import KEY from './KeyContext';

const url = 'http://www.omdbapi.com/?s='

const DataTable = ({ query = 'Harry Potter' }) => {
  const key = useContext(KEY);
  const [movies, setMovies] = useState([])
  useEffect(() => {
    fetch(`${url}${query}&apikey=${key}`)
      .then(r => r.json()).then(res => setMovies(res.Search.sort((a,b) => (a.Year-b.Year))))
  }, [key, query])

  return (
    <div>
      {movies.map(({Poster, Title, imdbID, Year}) => (
        <div key={imdbID}>
          <img src={Poster} height="100" alt={Title} />
          <p>
            <a href={`/?t=${imdbID}`}>{Title}</a>
            <br />{Year}
          </p>
        </div>
      ))}
    </div>
  )
}

export default DataTable

И если мы создадим компонент Wrapper, чтобы обернуть таблицу данных и передать данные как свойства; это будет выглядеть так:

import React, { useEffect, useState, useContext } from 'react';
import KEY from './KeyContext';

const url = 'http://www.omdbapi.com/?s='

const DataTable = ({ movies = []}) => (
  <div>
    {movies.map(({Poster, Title, imdbID, Year}) => (
      <div key={imdbID}>
        <img src={Poster} height="100" alt={Title} />
        <p>
          <a href={`/?t=${imdbID}`}>{Title}</a>
          <br />{Year}
        </p>
      </div>
    ))}
  </div>
)

const DataContainer = ({ query = 'Harry Potter' }) => {
  const key = useContext(KEY);
  const [movies, setMovies] = useState([])
  useEffect(() => {
    fetch(`${url}${query}&apikey=${key}`)
      .then(r => r.json()).then(res => setMovies(res.Search.sort((a,b) => (a.Year-b.Year))))
  }, [key, query])

  return <DataTable movies={movies} />
}

export default DataContainer

А теперь вот и кастомные крючки.

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

Кроме того, у нас может быть контекст для инициализации значений по умолчанию и некоторых общих данных для обмена между приложениями.

Прежде всего, мы хотим разделить загрузку данных. Давайте разберемся с новым крючком под названием useMovies

const useMovies = (query = null) => {
  return fetch(`${url}${query}&apikey=${key}`)
    .then(r => r.json())
    .then(r => r.Search.sort((a,b) => (a.Year-b.Year)))
}

Теперь, когда наша функция выполняет загрузку данных, давайте добавим ей постоянство с помощью хуков состояния.

import {useState} from 'react';

const useMovies = (query = null) => {
  const [movies, setMovies] = useState([])
  fetch(`${url}${query}&apikey=${key}`)
    .then(r => r.json())
    .then(r => r.Search.sort((a,b) => (a.Year-b.Year)))
    .then(setMovies)
  return movies;
}

Но мы хотим загружать фильмы при первом вызове, а не при каждом вызове; а затем получить новые данные при изменении запроса.

Вместе с тем, давайте выделим код извлечения / AJAX в отдельный файл.

С указанным выше разделением проблем в коде; у нас есть следующий useMovies хук и request модуль соответственно:

// useMovies.js
import { useState, useEffect, useContext } from 'react';
import KeyContext from './KeyContext';
import request from './request';
import queryString from 'query-string';

const url = 'http://www.omdbapi.com/'

const sortMovies = (movies = []) => movies.sort((a, b) => (a.Year - b.Year))

const getUrl = (params) => [url, queryString.stringify(params)].join('?')

const useMovies = (query = null) => {
  const [q, setQuery] = useState(query)
  const [movies, setMovies] = useState([]);
  const apikey = useContext(KeyContext);

  useEffect(() => {
    q && request(getUrl({ apikey, s: q }))
    .then(r => r.Search)
    .then(sortMovies)
    .then(setMovies)
  }, [q, apikey])

  return [movies, setQuery];
}

export default useMovies;
// request.js
export default (url, params) => fetch(url, params)
  .then(response => {
    if (response.status === 200) {
      try {
        return response.json()
      } catch (e) {
        return response.text()
      }
    }
    return response
  })

В приведенной выше функции нашего настраиваемого хука мы сделали следующее:

  • Получите первый запрос и инициализируйте состояние для получения изменений в запросе
  • Данные фильмов с использованием useState Hook
  • Ключ API из контекста и хука useContext
  • Используйте useEffect для
  1. Запуск первого запроса для первого запроса
  2. Запросить изменения в API при изменении запроса
  3. Поскольку API-ключ поступает из контекста, он подвержен изменениям и, следовательно, сохраняет его в зависимости от useEffect хука.
  4. Верните данные (например, movies) и функцию для изменения запроса (например, setQuery)

Хотя при создании или использовании хуков необходимо помнить о двух правилах.

  1. Только вызовы на верхнем уровне
  2. Вызов хуков только из функций React

Названия правил достаточно, но вы можете прочитать о них подробнее здесь: Rules of Hooks - React

Более того, если вы просто хотите использовать хуки в большинстве случаев, вы можете проверить следующий репозиторий; это набор пользовательских хуков почти для всего: https://github.com/streamich/react-use

Вывод

Хуки значительно упростили код с точки зрения написания и чтения.

Я лично стараюсь использовать хуки как можно чаще.

Я хотел бы знать, вы сделали свой собственный крючок? И как?

Дайте мне знать в комментариях 💬 или в Твиттере на @patel_pankaj_ и / или @ time2hack

Если вы найдете эту статью полезной, поделитесь ею с другими 🗣

Подпишитесь на блог, чтобы получать новые сообщения прямо на свой почтовый ящик.

Кредиты

Иконка из IconFinder
Фото Ferenc Almasi на Unsplash

Первоначально опубликовано на https://time2hack.com 21 июля 2020 г.