如图所示,获取数据并将其显示在屏幕上后,橙色按钮出现(中间)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 handleChangeCategory = useCallback((index: number) => {
dispatch(setCategoryID(index))
dispatch(setCurrentPage(1))
}, [])
const handleChangePage = (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
handleChangeCategory={handleChangeCategory}
value={categoryID}
/>
<Sort sortNameObj={sortNameObj} />
</div>
<h2>Все пиццы</h2>
<section className={styles.content__list}>{loadedPizzas}</section>
<Pagination
handleChangePage={handleChangePage}
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秒?
您可以在 useEffect 上放置 setTimeout(() =>dispatch(fetchPizzas()), 1000),或者,如果这些函数中的任何一个是异步的,您可以使用 State 有条件地渲染或不渲染组件。在返回要延迟的组件的地方,请执行以下操作: return shouldRenderPizza ? (你实际的披萨成分):
现在,在你的 useEffect 上做一些像dispatch(fetchPizzas().then(result => setTimeout(() => setShouldRenderPizza(true), 1000)))这样的事情
当
EmptyResult
为 true 并且 loading
状态为 false 或为空时,当前显示 pizzas
组件。 pizzas
状态最初为空,并且当 []
操作待处理时也设置为 fetchPizzas
。
如果您只想在加载数据后显示
EmptyResult
,请从 []
- “获取数据并清空”和 [....]
- “获取数据并填充”中选择一个 different值,以区分状态和加载状况。此处使用
undefined
或 null
是有效的选择,表示数据尚未获取/加载,并且很容易在 UI 中检查。
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;
});
},
});
更新 UI 以检查
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 handleChangeCategory = useCallback((index: number) => {
dispatch(setCategoryID(index));
dispatch(setCurrentPage(1));
}, []);
useEffect(() => {
dispatch(fetchPizzas())
}, [categoryID, searchValue, sortNameObj, currentPage])
const handleChangePage = (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='Пиццы не найдены' />;
}
const pizzaList = pizzas?.map((item) => (
<PizzaCard
key={item.id}
item={item}
pizzaImg={pizzaImagesMiddle[item.title]}
/>
));
const loadedPizzas = loading ? skeletons : pizzaList;
return (
<div className={styles.home__container}>
<div className={styles.content__header}>
<Categories
handleChangeCategory={handleChangeCategory}
value={categoryID}
/>
<Sort sortNameObj={sortNameObj} />
</div>
<h2>Все пиццы</h2>
<section className={styles.content__list}>
{loadedPizzas}
</section>
<Pagination
handleChangePage={handleChangePage}
currentPage={currentPage}
itemsLength={count}
/>
</div>
);
};