Я делал это таким образом, но некоторые колледжи сказали мне, что вместо этого я должен использовать крючок 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.info('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
Итак, я наконец нашел преимущество этого подхода. У меня есть код, который нужно изменить... Большое спасибо за ответы!





Прямо сейчас, если ваш компонент выполняет повторную визуализацию до того, как он установил данные, он попытается снова получить данные, что приведет к множественной выборке. Учитывая, что вы хотите получить данные только один раз, а не случайно несколько раз, было бы лучше поместить их в useEffect.
То, что вы написали, вроде работает. Вы говорите: «Если выборка не удалась и компонент повторно отображается, попробуйте еще раз, иначе не делайте этого». Лично я считаю, что это ненадежная система - в зависимости от повторного рендеринга, чтобы повторить попытку, и легко может иметь непреднамеренные побочные эффекты:
Что делать, если ваши данные ложные? Что, если это не удастся (с которым вы не справились). В этом случае он будет продолжать попытки повторной загрузки.
Что делать, если родитель рендерится 3 раза подряд (очень распространенная ситуация). В этом случае ваша выборка произойдет 3 раза, прежде чем первая выборка будет завершена.
Поэтому, имея это в виду, вам на самом деле нужны более тщательные проверки, чтобы убедиться, что ваш код не имеет неожиданных последствий, не используя useEffect. Кроме того, если ваша выборка хотела повторно получить изменения реквизита, ваше решение также не работает.
Вы должны использовать useEffect, потому что то, что вы делаете, является анти-шаблоном. На веб-сайте реакции вы можете ясно видеть, почему используется useEffect:
Data fetching, setting up a subscription, and manually changing the DOM in React components are all examples of side effects. Whether or not you’re used to calling these operations “side effects” (or just “effects”), you’ve likely performed them in your components before. https://reactjs.org/docs/hooks-effect.html
Компоненты React — это просто функции, которые принимают некоторые реквизиты и возвращают некоторые jsx. Если вы хотите иметь побочный эффект, вы не должны иметь его непосредственно в своем компоненте. Это должно быть в методе жизненного цикла.
Представьте, что ваша проверка условий (! data) была сложной, перебирающей массивы и т. д. Это оказало бы большее влияние на производительность. Но useEffect будет более производительным, и вы даже можете использовать второй аргумент для своего рода «кеширования» результатов.
Между двумя вашими компонентами существует технически без разницы, за исключением того, что проверка условия будет выполняться при каждом рендеринге в вашей версии. Тогда как useEffect будет вызываться только в «смонтированном», «обновленном» состоянии компонента.
Но у него есть условие на
data, он не будет получать каждый рендер, или я ошибаюсь? (Хотя я полностью согласен со всем остальным, это просто частный случай однократной выборки).