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
Теперь, если бы мы добавили запросы на загрузку данных и построили ссылки на профили, это можно было бы сделать двумя способами:
- Добавьте все запросы и функции в один компонент
- Создайте компонент-оболочку для
- Сделайте запрос и создайте ссылки
- Передайте все необходимые данные и функции как реквизиты
Давайте попробуем увидеть оба пути и то, как наш компьютер развивается в размерах и функциональных возможностях.
Загрузка данных, построение обработчиков событий и разметки в одном компоненте:
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 для
- Запуск первого запроса для первого запроса
- Запросить изменения в API при изменении запроса
- Поскольку API-ключ поступает из контекста, он подвержен изменениям и, следовательно, сохраняет его в зависимости от
useEffect
хука. - Верните данные (например,
movies
) и функцию для изменения запроса (например,setQuery
)
Хотя при создании или использовании хуков необходимо помнить о двух правилах.
- Только вызовы на верхнем уровне
- Вызов хуков только из функций React
Названия правил достаточно, но вы можете прочитать о них подробнее здесь: Rules of Hooks - React
Более того, если вы просто хотите использовать хуки в большинстве случаев, вы можете проверить следующий репозиторий; это набор пользовательских хуков почти для всего: https://github.com/streamich/react-use
Вывод
Хуки значительно упростили код с точки зрения написания и чтения.
Я лично стараюсь использовать хуки как можно чаще.
Я хотел бы знать, вы сделали свой собственный крючок? И как?
Дайте мне знать в комментариях 💬 или в Твиттере на @patel_pankaj_ и / или @ time2hack
Если вы найдете эту статью полезной, поделитесь ею с другими 🗣
Подпишитесь на блог, чтобы получать новые сообщения прямо на свой почтовый ящик.
Кредиты
Иконка из IconFinder
Фото Ferenc Almasi на Unsplash
Первоначально опубликовано на https://time2hack.com 21 июля 2020 г.