Как вы можете видеть на изображении, после получения данных и их отображения на экране, оранжевая кнопка появляется (в центре) на 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 секунду?
Кажется, возникла ситуация, когда загрузка идет false
, но переменная пиццы установлена неправильно. Это больше не является ложным, но его длина не равна 0. И если это так, то вы должны правильно их синхронизировать.
@Тушар Шахи, обновлено
вы можете либо поместить 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>
);
};
Давайте продолжим обсуждение в чате.
Чтобы помочь вам лучше, можете ли вы поделиться остальной частью кода. Хотите посмотреть, как установлены значения
loading
,pizzas