Cache oder Status, versuchen Sie React-Query

Himmel und Meer
Himmel und Meer

EinfĂŒhrung

Eine beliebte Bibliothek fĂŒr die Arbeit mit dem Status von Webanwendungen in React-Js ist Redux. Es hat jedoch eine Reihe von Nachteilen wie die AusfĂŒhrlichkeit (auch in Verbindung mit dem Redux-Toolkit) und die Notwendigkeit, eine zusĂ€tzliche Ebene auszuwĂ€hlen (Redux-Thunk, Redux-Saga, Redux-Observable). Es besteht das GefĂŒhl, dass dies irgendwie allzu kompliziert ist und es lange Zeit Hooks gab, insbesondere den useContext-Hook. Also habe ich eine andere Lösung ausprobiert.





Anwendung testen 

« » create react app, typescript, redux-toolkit, redux saga. redux context + react-query. , , , react-query  . .. , .. ,   . .. .





Anwendungsbildschirme testen

 

react-query , , .. redux 2 . — , . — , . 





react-context. :





export const CitiesProvider = ({
  children,
}: {
  children: React.ReactNode;
}): JSX.Element => {
  const [citiesState, setCitiesState] = useLocalStorage<CitiesState>(
    'citiesState',
    citiesStateInitValue,
  );

  const addCity = (id: number) => {
    if (citiesState.citiesList.includes(id)) {
      return;
    }
    setCitiesState(
      (state: CitiesState): CitiesState => ({
        ...state,
        citiesList: [...citiesState.citiesList, id],
      }),
    );
  };
 // removeCity..,  setCurrentCity..

  return (
    <itiesContext.Provider
      value={{
        currentCity: citiesState.currentCity,
        cities: citiesState.citiesList,
        addCity,
        removeCity,
        setCurrentCity,
      }}
    >
      {children}
    </itiesContext.Provider>
  );
};

      
      



, setCurrentCity, removeCity



. , localStorage . , , , , .





React-query

, , react-query.   :





import { QueryClient, QueryClientProvider } from 'react-query';
import { ReactQueryDevtools } from 'react-query/devtools';
 
import { CitiesProvider } from './store/cities/cities-provider';
 
const queryClient = new QueryClient();
 
ReactDOM.render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <CitiesProvider>
        <App />
      
      



:





const queryCities = useQuery('cities', fetchCitiesFunc);
const cities = queryCities.data || [];
      
      



'cities'



, . - , Promise, . .





useQuery UseQueryResult



, ,





const { isLoading, isIdle, isError, data, error } = useQuery(..
      
      







export function useCurrentWeather(): WeatherCache {
  const { currentCity } = useContext(itiesContext);
 
 //   
  const queryCities = useQuery('cities', fetchCitiesFunc, {
     refetchOnWindowFocus: false,
    staleTime: 1000 * 60 * 1000,
  });
  const citiesRu = queryCities.data || [];
 
//    .. 
 const city = citiesRu.find((city) => {
    if (city === undefined) return false;
    const { id: elId } = city;
    if (currentCity === elId) return true;
    return false;
  });
 
  const { id: weatherId } = city ?? {};
 
 //   
  const queryWeatherCity = useQuery(
    ['weatherCity', weatherId],
    () => fetchWeatherCityApi(weatherId as number),
    {
      enabled: !!weatherId,
      staleTime: 5 * 60 * 1000,
    },
  );
 
  const { coord } = queryWeatherCity.data ?? {};
 
 //      . 
  const queryForecastCity = useQuery(
    ['forecastCity', coord],
    () => fetchForecastCityApi(coord as Coord),
    {
      enabled: !!coord,
      staleTime: 5 * 60 * 1000,
    },
  );
 
  return {
    city,
    queryWeatherCity,
    queryForecastCity,
  };
}
      
      



staleTime



— , , . , . , staleTime =0



.





 enabled: !!weatherId



, . useQuery



isIdle



. .





const queryWeatherCity = useQuery(['weatherCity', weatherId],.. 
      
      



, , + .





:





export function Forecast(): React.ReactElement {
  const {
    queryForecastCity: { isFetching, isLoading, isIdle, data: forecast },
  } = useCurrentWeather();
 
  if (isIdle) return <LoadingInfo text="   " />;
  if (isLoading) return <LoadingInfo text="  " />;
 
  const { daily = [], alerts = [], hourly = [] } = forecast ?? {};
  const dailyForecastNext = daily.slice(1) || [];
 
  return (
    <>
      <Alerts alerts={alerts} />
      <HourlyForecast hourlyForecast={hourly} />
      <DailyForecast dailyForecast={dailyForecastNext} />
      {isFetching && <LoadingInfo text="  " />}
    </>
  );
}
      
      



isLoading — isFetching - .





React-query . Redux, ( ) 





Fenster fĂŒr Entwicklertools

, Actions, , , .. , , , . . :





import { ReactQueryDevtools } from 'react-query/devtools';
      
      



, process.env.NODE_ENV === 'production'



,  . Create React App .





react-query , , , .





  • useQueries



    . .. useQuery



    .





const userQueries = useQueries(
  users.map(user => {
    return {
      queryKey: ['user', user.id],
      queryFn: () => fetchUserById(user.id),
    }
  })
      
      



  • , , 3 . retry



    .





  • , , useMutations







const mutation = useMutation(newTodo => axios.post('/todos', newTodo))
      
      



  • , useInfiniteQuery







  • , , , .





Nach dem Ersetzen von Redux-Toolkit + Redux-Saga und Kontext + React-Query schien mir der Code viel einfacher zu sein, und ich hatte sofort mehr Funktionen fĂŒr die Arbeit mit Anfragen an den Server. Der React-Context-Teil verfĂŒgt jedoch nicht ĂŒber spezielle Debugging-Tools und wirft im Allgemeinen Bedenken auf. Er erwies sich jedoch als recht klein und React-Devtools waren genug fĂŒr mich. Im Allgemeinen bin ich mit der React-Query-Bibliothek zufrieden, und im Allgemeinen erscheint mir die Idee, den Cache in eine separate EntitĂ€t zu unterteilen, interessant. Trotzdem ist dies eine sehr kleine Anwendung mit mehreren Get-Anfragen.   





Links

Das Layout ist nur fĂŒr mobile GerĂ€te korrekt





Es gibt einen Zweig mit Redux





React-Query-Dokumentation








All Articles