refactor(core): optimize state management and component rendering performance
Improve application stability and performance by optimizing Zustand store usage, implementing memoization patterns, and introducing persistent authentication. - **State Management**: - Refactor Zustand selectors to use `useShallow` and `getState()` to prevent unnecessary re-renders and infinite loops in hooks. - Implement `persist` middleware for `authStore` to maintain user sessions across restarts. - Introduce `buildStateCached` in `themeStore` to reduce redundant theme object computations. - **Performance & Rendering**: - Implement `useMemo` for stable object/array references in `ImageGallery` and list components to prevent expensive re-renders. - Replace inline arrow functions with `useCallback` in complex screens like `ChatScreen` and `MessageListScreen`. - Optimize `FlashList` usage by providing stable `key` and `extraData` props. - **Architecture**: - Decouple unread count fetching by introducing `useUnreadCountQuery` (React Query) for better caching and synchronization. - Add `useChannels` hook to centralize channel data fetching. - Refine `SessionGate` logic to allow immediate rendering of authenticated users while verifying in the background.
This commit is contained in:
@@ -29,6 +29,7 @@ import { Post } from '../../types';
|
||||
import { useUserStore, useHomeTabBarVisibilityStore, useHomeTabPressStore } from '../../stores';
|
||||
import { useCurrentUser, useIsAuthenticated, useIsVerified, useVerificationStore } from '../../stores/auth';
|
||||
import { channelService, postService } from '../../services';
|
||||
import { useChannels } from '../../hooks/useChannels';
|
||||
import { PostCard, SearchBar, ShareSheet } from '../../components/business';
|
||||
import type { PostCardAction } from '../../components/business/PostCard';
|
||||
import { Loading, EmptyState, Text, ImageGallery, ImageGridItem } from '../../components/common';
|
||||
@@ -215,7 +216,7 @@ function createHomeStyles(colors: AppColors, responsivePadding: number) {
|
||||
export const HomeScreen: React.FC = () => {
|
||||
const router = useRouter();
|
||||
const insets = useSafeAreaInsets();
|
||||
const { posts: storePosts } = useUserStore();
|
||||
const storePosts = useUserStore((s) => s.posts);
|
||||
const currentUser = useCurrentUser();
|
||||
const isAuthenticated = useIsAuthenticated();
|
||||
const isVerified = useIsVerified();
|
||||
@@ -242,13 +243,23 @@ export const HomeScreen: React.FC = () => {
|
||||
|
||||
const [sortIndex, setSortIndex] = useState(2);
|
||||
const [viewMode, setViewMode] = useState<ViewMode>('list');
|
||||
const [latestCapsules, setLatestCapsules] = useState<LatestCapsule[]>([{ id: '', name: '全部' }]);
|
||||
const { data: channelList = [] } = useChannels();
|
||||
const latestCapsules = useMemo<LatestCapsule[]>(
|
||||
() => [{ id: '', name: '全部' }, ...channelList.map(item => ({ id: item.id, name: item.name }))],
|
||||
[channelList]
|
||||
);
|
||||
const [activeCapsuleId, setActiveCapsuleId] = useState('');
|
||||
|
||||
|
||||
// 图片查看器状态
|
||||
const [showImageViewer, setShowImageViewer] = useState(false);
|
||||
const [postImages, setPostImages] = useState<ImageGridItem[]>([]);
|
||||
const [selectedImageIndex, setSelectedImageIndex] = useState(0);
|
||||
|
||||
const stableCloseImageViewer = useCallback(() => setShowImageViewer(false), []);
|
||||
const stableGalleryImages = useMemo(() => postImages.map((img, i) => ({
|
||||
id: img.id || img.url || `img-${i}`,
|
||||
url: img.url || img.uri || ''
|
||||
})), [postImages]);
|
||||
|
||||
// 搜索显示状态(用于内嵌搜索页面)
|
||||
const [showSearch, setShowSearch] = useState(false);
|
||||
@@ -587,18 +598,6 @@ export const HomeScreen: React.FC = () => {
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const loadChannels = async () => {
|
||||
const list = await channelService.list();
|
||||
const capsules: LatestCapsule[] = [
|
||||
{ id: '', name: '全部' },
|
||||
...list.map(item => ({ id: item.id, name: item.name })),
|
||||
];
|
||||
setLatestCapsules(capsules);
|
||||
};
|
||||
loadChannels();
|
||||
}, []);
|
||||
|
||||
// 跳转到搜索页(使用内嵌模式,不再依赖导航)
|
||||
const handleSearchPress = () => {
|
||||
setShowSearch(true);
|
||||
@@ -811,9 +810,10 @@ export const HomeScreen: React.FC = () => {
|
||||
const renderResponsiveGrid = () => {
|
||||
return (
|
||||
<FlashList
|
||||
key={`${listKey}_grid`}
|
||||
key="home-grid"
|
||||
ref={scrollViewRef as any}
|
||||
data={displayPosts}
|
||||
extraData={listKey}
|
||||
renderItem={renderGridItem}
|
||||
keyExtractor={keyExtractor}
|
||||
numColumns={gridColumns}
|
||||
@@ -865,9 +865,10 @@ export const HomeScreen: React.FC = () => {
|
||||
// 移动端和宽屏都使用单列 FlashList,宽屏下居中显示
|
||||
return (
|
||||
<FlashList
|
||||
key={listKey}
|
||||
key="home-list"
|
||||
ref={flashListRef}
|
||||
data={displayPosts}
|
||||
extraData={listKey}
|
||||
renderItem={renderPostList}
|
||||
keyExtractor={keyExtractor}
|
||||
contentContainerStyle={{
|
||||
@@ -1062,12 +1063,9 @@ export const HomeScreen: React.FC = () => {
|
||||
{/* 图片查看器 */}
|
||||
<ImageGallery
|
||||
visible={showImageViewer}
|
||||
images={postImages.map(img => ({
|
||||
id: img.id || img.url || String(Math.random()),
|
||||
url: img.url || img.uri || ''
|
||||
}))}
|
||||
images={stableGalleryImages}
|
||||
initialIndex={selectedImageIndex}
|
||||
onClose={() => setShowImageViewer(false)}
|
||||
onClose={stableCloseImageViewer}
|
||||
enableSave
|
||||
/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user