Как избежать вспышки ненужного компонента в течение 1 секунды после получения данных в React?

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

Код компонента:

const Home: FC = () => {
    const { pizzas, loading, error, count } = useAppSelector(
        (state) => state.pizzas
    )
    const { categoryID, searchValue, currentPage, sortNameObj } =
        useAppSelector((state) => state.filter)
    const dispatch = useAppDispatch()

    const handleChangeEventCategory = useCallback((index: number) => {
        dispatch(setCategoryID(index))
        dispatch(setCurrentPage(1))
    }, [])

    const handleChangeEventPage = (page: number) => {
        dispatch(setCurrentPage(page))
    }

    const pizzaList = pizzas?.map((item) => {
        const pizzaImg = pizzaImagesMiddle[item.title]

        return <PizzaCard key = {item.id} item = {item} pizzaImg = {pizzaImg} />
    })

    const skeletons = [...new Array(4)].map((_, index) => (
        <PizzaSkeleton key = {index} />
    ))

    const loadedPizzas = loading ? skeletons : pizzaList

    useEffect(() => {
        dispatch(fetchPizzas())
    }, [categoryID, searchValue, sortNameObj, currentPage])

    if (error) {
        return <EmptyResult title='Произошла ошибка' />
    }

    if (!loading && (!pizzas || pizzas?.length === 0)) {
        return <EmptyResult title='Пиццы не найдены' />
    }

    return (
        <div className = {styles.home__container}>
            <div className = {styles.content__header}>
                <Categories
                    handleChangeEventCategory = {handleChangeEventCategory}
                    value = {categoryID}
                />
                <Sort sortNameObj = {sortNameObj} />
            </div>
            <h2>Все пиццы</h2>
            <section className = {styles.content__list}>{loadedPizzas}</section>
            <Pagination
                handleChangeEventPage = {handleChangeEventPage}
                currentPage = {currentPage}
                itemsLength = {count}
            />
        </div>
    )
}

Потому что проверяем длину пиццы в состоянии if (!loading && (!pizzas || pizzas?.length === 0)). Без проверки пустой длины if (!loading && !pizzas) все идет хорошо. Но мне нужно проверить, пуст ли массив или нет.

По умолчанию длина пиццы пуста (поэтому перед получением данных у меня есть пустой массив)

Кусок пиццы:

const initialState: PizzasState = {
    pizzas: [],
    loading: false,
    error: null,
    count: 0
}

const pizzasSlice = createSlice({
    name: 'pizzas',
    initialState,
    reducers: {},
    extraReducers: (builder) => {
        builder.addCase(fetchPizzas.pending, (state) => {
            state.loading = true;
            state.pizzas = [];
            state.error = null;
            state.count = 0
        });
        builder.addCase(fetchPizzas.fulfilled, (state, action) => {
            state.pizzas = action.payload.items;
            state.error = null;
            state.count = action.payload.count;
            state.loading = false
        });
        builder.addCase(fetchPizzas.rejected, (state, action) => {
            state.pizzas = [];
            state.count = 0;
            if (action.payload) {
                state.error = action.payload.message
            } else {
                state.error = action.error.message
            };
            state.loading = false
        })
    }
})

Вопрос: Как правильно избежать мигания <EmptyResult/> на 1 секунду?

Чтобы помочь вам лучше, можете ли вы поделиться остальной частью кода. Хотите посмотреть, как установлены значения loading, pizzas

Tushar Shahi 16.04.2024 17:20

Кажется, возникла ситуация, когда загрузка идет false, но переменная пиццы установлена ​​неправильно. Это больше не является ложным, но его длина не равна 0. И если это так, то вы должны правильно их синхронизировать.

Tushar Shahi 16.04.2024 17:24

@Тушар Шахи, обновлено

rgdzv 16.04.2024 17:31
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
3
52
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

вы можете либо поместить setTimeout(() => send(fetchPizzas()), 1000) в свой useEffect, либо, если какая-либо из этих функций является асинхронной, вы можете использовать State для условной визуализации компонента или нет. Там, где вы возвращаете компонент, который хотите отложить, сделайте что-то вроде: return mustRenderPizza? (ваш фактический компонент пиццы):

теперь в вашем useEffect сделайте что-то вроде диспетчеризации (fetchPizzas().then(result => setTimeout(() => setShouldRenderPizza(true), 1000)))

Ответ принят как подходящий

Проблема

Компонент EmptyResult в настоящее время отображается, когда loading истинно, а состояние pizzas ложно или пусто. Состояние pizzas изначально пусто, а также устанавливается в [], когда действие fetchPizzas находится в ожидании.

Решение

Если вы хотите отображать EmptyResult только после загрузки данных, выберите другое значение: [] — «полученные данные и пустые» и [....] — «полученные данные и заполненные», чтобы различать состояния и условия загрузки. Здесь можно использовать undefined или null, чтобы указать, что данные еще не были получены/загружены и что их легко проверить в пользовательском интерфейсе.

const initialState: PizzasState = {
  pizzas: undefined, // <-- initially undefined
  loading: false,
  error: null,
  count: 0,
};

const pizzasSlice = createSlice({
  name: 'pizzas',
  initialState,
  extraReducers: (builder) => {
    builder.addCase(fetchPizzas.pending, (state) => {
      state.loading = true;
      // state.pizzas = []; // <-- Don't update yet
      state.error = null;
      state.count = 0
    });
    builder.addCase(fetchPizzas.fulfilled, (state, action) => {
      state.pizzas = action.payload.items; // <-- update to "loaded" value
      state.error = null;
      state.count = action.payload.count;
      state.loading = false;
    });
    builder.addCase(fetchPizzas.rejected, (state, action) => {
      state.pizzas = []; // <-- update to "loaded" value
      state.count = 0;
      state.error = action.payload
        ? action.payload.message
        : action.error.message;
      state.loading = false;
    });
  },
});

Обновите пользовательский интерфейс, чтобы проверить наличие загруженных данных undefined/null.

const skeletons = [...new Array(4)].map((_, index) => (
  <PizzaSkeleton key = {index} />
));

const Home: FC = () => {
  const { pizzas, loading, error, count } =
    useAppSelector((state) => state.pizzas);
  const { categoryID, searchValue, currentPage, sortNameObj } =
    useAppSelector((state) => state.filter);
  const dispatch = useAppDispatch();

  const handleChangeEventCategory = useCallback((index: number) => {
    dispatch(setCategoryID(index));
    dispatch(setCurrentPage(1));
  }, []);

  useEffect(() => {
    dispatch(fetchPizzas())
  }, [categoryID, searchValue, sortNameObj, currentPage])

  const handleChangeEventPage = (page: number) => {
    dispatch(setCurrentPage(page));
  };

  if (error) {
    return <EmptyResult title='Произошла ошибка' />;
  }

  // Check if pizzas is a defined array and empty
  if (!loading && (Array.isArray(pizzas) && !pizzas.length)) {
    return <EmptyResult title='Пиццы не найдены' />;
  }

  return (
    <div className = {styles.home__container}>
      <div className = {styles.content__header}>
        <Categories
          handleChangeEventCategory = {handleChangeEventCategory}
          value = {categoryID}
        />
        <Sort sortNameObj = {sortNameObj} />
      </div>
      <h2>Все пиццы</h2>
      <section className = {styles.content__list}>
        {loading
          ? skeletons
          : pizzas?.map((item) => (
            <PizzaCard
              key = {item.id}
              item = {item}
              pizzaImg = {pizzaImagesMiddle[item.title]}
            />
          ))
        }
      </section>
      <Pagination
        handleChangeEventPage = {handleChangeEventPage}
        currentPage = {currentPage}
        itemsLength = {count}
      />
    </div>
  );
};

Давайте продолжим обсуждение в чате.

Drew Reese 16.04.2024 18:54

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