我在ReactNative中用Suspense
和startTransition
做了一个简单的菜单/细节示例
import React, {useState, Suspense, startTransition} from 'react';
import {
Button,
Details,
Heading,
Menu,
Text,
Wrapper,
} from './StarWarsSuspenseApp.styled';
import {QueryClient, QueryClientProvider, useQuery} from 'react-query';
const api = (entity: 'planets') => `https://swapi.dev/api/${entity}`;
const EMPTY = '';
type Planet = {
name: string;
rotation_period: string;
orbital_period: string;
diameter: string;
climate: string;
gravity: string;
terrain: string;
surface_water: string;
population: string;
residents: string[];
films: string[];
created: string;
edited: string;
url: string;
};
type ApiResponse<K> = {
count: number;
next: string;
previous: null;
results: K;
};
const queryClient = new QueryClient({
defaultOptions: {
queries: {
suspense: true,
},
},
});
const fetchWithErrors = async <T,>(request: Promise<Response>): Promise<T> => {
const response = await request;
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json() as Promise<T>;
};
const fetchPlanets = () =>
fetchWithErrors<ApiResponse<Planet[]>>(fetch(api('planets')));
const usePlanets = () => useQuery('planets', fetchPlanets);
const fetchPlanetDetails = (url: string) =>
fetchWithErrors<ApiResponse<Planet>>(fetch(url));
const usePlanetDetails = (url: string) =>
useQuery(['planet', url], () => fetchPlanetDetails(url), {
enabled: url !== EMPTY,
});
const Screen = () => {
const [selectedUrl, setSelectedUrl] = useState(EMPTY);
const planets = usePlanets();
const planetDetails = usePlanetDetails(selectedUrl);
const handlePlanetSelect = (url: string) => {
startTransition(() => {
setSelectedUrl(url);
});
};
return (
<Wrapper>
<Suspense fallback={<Heading>Loading Planets...</Heading>}>
{planets.isLoading ? (
<Heading>Loading...</Heading>
) : planets.isError ? (
<Heading>{`${planets.error}`}</Heading>
) : (
<Menu>
{planets?.data?.results.map(planet => (
<Button
key={planet.name}
title={planet.name}
onPress={() => handlePlanetSelect(planet.url)}
/>
))}
</Menu>
)}
</Suspense>
{selectedUrl !== EMPTY && (
<Suspense fallback={<Heading>Loading Planet Details...</Heading>}>
{planetDetails.isLoading ? (
<Heading>Loading Details...</Heading>
) : planetDetails.isError ? (
<Heading>{`${planetDetails.error}`}</Heading>
) : (
<Details>
<Text>{JSON.stringify(planetDetails.data, null, 2)}</Text>
</Details>
)}
</Suspense>
)}
</Wrapper>
);
};
const StarWarsSuspenseApp = () => (
<QueryClientProvider client={queryClient}>
<Screen />
</QueryClientProvider>
);
export default StarWarsSuspenseApp;
字符串
但我得到这个错误
Error: A component suspended while responding to synchronous input. This will cause the UI to be replaced with a loading indicator. To fix, updates that suspend should be wrapped with startTransition.
This error is located at:
in Screen (created by StarWarsSuspenseApp)
in QueryClientProvider (created by StarWarsSuspenseApp)
in StarWarsSuspenseApp (created by Routes)
in RenderedRoute (created by Routes)
in Routes (created by App)
in Router (created by MemoryRouter)
in MemoryRouter (created by NativeRouter)
in NativeRouter (created by App)
in RCTSafeAreaView (created by SafeAreaView)
in Styled(RCTSafeAreaView) (created by App)
in App
in RCTView (created by View)
in View (created by AppContainer)
in RCTView (created by View)
in View (created by AppContainer)
in AppContainer
in Toy(RootComponent), js engine: hermes
型
包
"react": "18.2.0",
"react-native": "0.72.7",
"react-query": "3.39.3",
型
有人能看出问题吗?
1条答案
按热度按时间cyvaqqii1#
handlePlanetSelect
函数是响应用户操作而调用的,应该 Package 在startTransition
中:字符串