Синхронизация между экранами
Когда данные меняются на одном экране, другие должны обновиться.
TanStack Query — автоматически
Если оба экрана используют useQuery с одним ключом — данные синхронизированы:
// Экран 1
const { data } = useQuery({ queryKey: ['posts'], queryFn: fetchPosts });
// Экран 2
const { data } = useQuery({ queryKey: ['posts'], queryFn: fetchPosts });
Изменение на одном экране → инвалидация → оба обновятся.
Инвалидация после мутации
const mutation = useMutation({
mutationFn: createPost,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['posts'] });
},
});
Все экраны с ['posts'] перезагрузят данные.
Refetch при фокусе
useFocusEffect(
useCallback(() => {
queryClient.invalidateQueries({ queryKey: ['posts'] });
}, [queryClient])
);
При возврате на экран — свежие данные.
Глобальный стор
Если данные в Zustand — все экраны видят изменения автоматически:
const count = useCartStore((s) => s.items.length);
События
Иногда нужен обмен событиями:
import { DeviceEventEmitter } from 'react-native';
// на одном экране
DeviceEventEmitter.emit('post-created', { id: 5 });
// на другом
useEffect(() => {
const sub = DeviceEventEmitter.addListener('post-created', (data) => {
console.log('создан пост', data.id);
});
return () => sub.remove();
}, []);
Мини-эмиттер
// lib/events.ts
type Listener = (...args: unknown[]) => void;
const listeners = new Map<string, Set<Listener>>();
export const events = {
on(event: string, listener: Listener) {
if (!listeners.has(event)) listeners.set(event, new Set());
listeners.get(event)!.add(listener);
return () => listeners.get(event)?.delete(listener);
},
emit(event: string, ...args: unknown[]) {
listeners.get(event)?.forEach((l) => l(...args));
},
};
Использование:
events.emit('cart-updated');
useEffect(() => events.on('cart-updated', refetch), []);
Навигация с параметрами
Передать данные при возврате:
// на экране редактирования
navigation.navigate('List', { refresh: true });
// на экране списка
useEffect(() => {
if (route.params?.refresh) {
refetch();
}
}, [route.params?.refresh]);
Или navigation.popTo('List', { refresh: true }).
Оптимистичные обновления
Если данные меняются на нескольких экранах, оптимистичное обновление делает UI мгновенным:
onMutate: async (newPost) => {
queryClient.setQueryData(['posts'], (old: Post[]) => [...old, newPost]);
}
Что выбрать
- TanStack Query — для серверных данных
- Zustand — для клиентского
- Event emitter — для точечных событий
- Параметры навигации — для разовых сигналов
Итоги
- TanStack Query синхронизирует автоматически
invalidateQueriesпосле мутацийuseFocusEffectдля refetch- Zustand для клиентского состояния
- Event emitter для точечных событий