React Native 悬念抱怨startTransition,但我正在使用它

6qfn3psc  于 6个月前  发布在  React
关注(0)|答案(1)|浏览(63)

我在ReactNative中用SuspensestartTransition做了一个简单的菜单/细节示例

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",


有人能看出问题吗?

cyvaqqii

cyvaqqii1#

handlePlanetSelect函数是响应用户操作而调用的,应该 Package 在startTransition中:

const handlePlanetSelect = (url: string) => {
  startTransition(() => {
    setSelectedUrl(url);
  });
};

字符串

相关问题