···36363737**App Development**
38383939+Building the Android version requires Java 17. On Ubuntu you can run
4040+`sudo apt install openjdk-17-jdk`.
4141+3942```
4043cd js/app
4144
···11+// This file serves as a central hub for re-exporting pre-typed Redux hooks.
22+// These imports are restricted elsewhere to ensure consistent
33+// usage of typed hooks throughout the application.
44+// We disable the ESLint rule here because this is the designated place
55+// for importing and re-exporting the typed versions of hooks.
66+/* eslint-disable @typescript-eslint/no-restricted-imports */
77+import { useDispatch, useSelector } from "react-redux";
88+import type { AppDispatch, RootState } from "./store";
99+1010+// Use throughout your app instead of plain `useDispatch` and `useSelector`
1111+export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
1212+export const useAppSelector = useSelector.withTypes<RootState>();
+53
js/app/store/store.tsx
···11+import type { Action, ThunkAction } from "@reduxjs/toolkit";
22+import { combineSlices, configureStore } from "@reduxjs/toolkit";
33+import { setupListeners } from "@reduxjs/toolkit/query";
44+import { aquareumSlice } from "features/aquareum/aquareumSlice";
55+import { blueskySlice } from "features/bluesky/blueskySlice";
66+// import { counterSlice } from "../features/counter/counterSlice"
77+// import { quotesApiSlice } from "../features/quotes/quotesApiSlice"
88+99+// `combineSlices` automatically combines the reducers using
1010+// their `reducerPath`s, therefore we no longer need to call `combineReducers`.
1111+const rootReducer = combineSlices(blueskySlice, aquareumSlice);
1212+// Infer the `RootState` type from the root reducer
1313+export type RootState = ReturnType<typeof rootReducer>;
1414+1515+// The store setup is wrapped in `makeStore` to allow reuse
1616+// when setting up tests that need the same store config
1717+export const makeStore = (preloadedState?: Partial<RootState>) => {
1818+ const store = configureStore({
1919+ reducer: rootReducer,
2020+ // Adding the api middleware enables caching, invalidation, polling,
2121+ // and other useful features of `rtk-query`.
2222+ middleware: (getDefaultMiddleware) => {
2323+ return getDefaultMiddleware({
2424+ serializableCheck: {
2525+ // Ignore these action types
2626+ ignoredActions: [],
2727+ // Ignore these field paths in all actions
2828+ ignoredActionPaths: ["payload"],
2929+ // Ignore these paths in the state
3030+ ignoredPaths: [/^bluesky\..*/],
3131+ },
3232+ });
3333+ },
3434+ preloadedState,
3535+ });
3636+ // configure listeners using the provided defaults
3737+ // optional, but required for `refetchOnFocus`/`refetchOnReconnect` behaviors
3838+ setupListeners(store.dispatch);
3939+ return store;
4040+};
4141+4242+export const store = makeStore();
4343+4444+// Infer the type of `store`
4545+export type AppStore = typeof store;
4646+// Infer the `AppDispatch` type from the store itself
4747+export type AppDispatch = AppStore["dispatch"];
4848+export type AppThunk<ThunkReturnType = void> = ThunkAction<
4949+ ThunkReturnType,
5050+ RootState,
5151+ unknown,
5252+ Action
5353+>;