Неправильно ли получить API без использования useEffect Hook?
Я делал это таким образом, но некоторые колледжи сказали мне, что я должен использовать useEffect
Крюк вместо. Проблема в том, что я не вижу пользы от такого подхода и считаю, что мой подход чище.
import React, { useState, useEffect } from "react";
const fetchTheApi = () =>
new Promise(res => setTimeout(() => res({ title: "Title fetched" }), 3000));
const UseEffectlessComponent = () => {
const [data, setData] = useState();
!data && fetchTheApi().then(newData => setData(newData));
return <h1>{data ? data.title : "No title"}</h1>;
};
const UseEffectComponent = () => {
const [data, setData] = useState();
useEffect(() => {
fetchTheApi().then(newData => setData(newData));
}, []);
return <h1>{data ? data.title : "No title"}</h1>;
};
const MyComponent = () => (
<div>
<UseEffectlessComponent />
<UseEffectComponent />
</div>
);
Редактировать на основе ответов:
Я изменил код для рендеринга, вот так:
import React, { useState, useEffect } from 'react';
const fetchTheApi = (origin) => {
console.log('called from ' + origin);
return new Promise((res) =>
setTimeout(() => res({ title: 'Title fetched' }), 3000)
);
};
const UseEffectlessComponent = () => {
const [data, setData] = useState();
!data &&
fetchTheApi('UseEffectlessComponent').then((newData) => setData(newData));
return <h1>{data ? data.title : 'No title'}</h1>;
};
const UseEffectComponent = () => {
const [data, setData] = useState();
useEffect(() => {
fetchTheApi('UseEffectComponent').then((newData) => setData(newData));
}, []);
return <h1>{data ? data.title : 'No title'}</h1>;
};
const MyComponent = () => {
const [counter, setCounter] = useState(0);
counter < 3 && setTimeout(() => setCounter(counter + 1), 1000);
return (
<div>
<p>counter is: {counter}</p>
<UseEffectlessComponent />
<UseEffectComponent />
</div>
);
};
В консоли я получил:
called from UseEffectlessComponent
called from UseEffectComponent
called from UseEffectlessComponent
called from UseEffectlessComponent
called from UseEffectlessComponent
Итак, я наконец-то нашел пользу для такого подхода. У меня есть код для изменения... Большое спасибо за ответы!
3 ответа
Прямо сейчас, если ваш компонент выполняет рендеринг до того, как он установил данные, он попытается извлечь данные снова, что приведет к множественным выборкам. Учитывая, что вы хотите получать данные только один раз, а не случайно несколько раз, было бы лучше поместить их в useEffect.
Как вы это написали, вроде как работает. Вы говорите: "Если выборка не удалась и компонент повторно отрисовывается, попробуйте еще раз, иначе не делайте этого". Лично я считаю, что это ненадежная система - в зависимости от повторного рендеринга, который нужно повторить, и он может легко иметь непредвиденные побочные эффекты:
Что делать, если ваши данные ложны? Что, если это не удастся (с чем вы не справились). В этом случае он будет продолжать попытки повторной загрузки.
Что делать, если родительский рендеринг 3 раза подряд (очень распространенная ситуация). В этом случае ваша выборка произойдет 3 раза до завершения первой выборки.
Имея это в виду, вам действительно нужны более тщательные проверки, чтобы убедиться, что ваш код не имеет неожиданных последствий из-за отказа от useEffect. Кроме того, если ваша выборка хотела повторно получить при изменении опоры, ваше решение также не работает.
Вы должны использовать useEffect, потому что вы делаете анти-шаблон. С сайта реакции вы можете ясно увидеть, почему useEffect существует:
Выборка данных, настройка подписки и изменение DOM вручную в компонентах React - все это примеры побочных эффектов. Независимо от того, привыкли ли вы называть эти операции "побочными эффектами" (или просто "эффектами"), вы, вероятно, выполняли их раньше в своих компонентах. https://reactjs.org/docs/hooks-effect.html
Компоненты React - это просто функции, некоторые реквизиты и некоторые jsx. Если вы хотите иметь побочный эффект, вы не должны иметь его непосредственно в вашем компоненте. Это должно быть в методе жизненного цикла.
Представьте себе, что проверка вашего состояния (! Data) была сложной, проходя по массивам и т. Д. Это оказало бы большее влияние на производительность. Но useEffect будет более производительным, и вы даже можете использовать второй аргумент для своего рода "кэширования" результатов.
Технически нет никакой разницы между вашими двумя компонентами, за исключением того, что проверка условий будет выполняться при каждом рендере в вашей версии. Тогда как useEffect будет вызываться только в "смонтированных", "обновленных" состояниях компонента.