Неправильно ли получить 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 будет вызываться только в "смонтированных", "обновленных" состояниях компонента.

Другие вопросы по тегам