Skip to content

Commit

Permalink
Add StoreProvider for central coordination of side effects between sl…
Browse files Browse the repository at this point in the history
…ices (#431)
  • Loading branch information
burakcan authored Jul 15, 2023
1 parent 5630f44 commit fc1aba1
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 58 deletions.
7 changes: 3 additions & 4 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ import "@ionic/react/css/text-transformation.css";
import "@ionic/react/css/flex-utils.css";
import "@ionic/react/css/display.css";

import { Provider } from "react-redux";
import store from "./store";
import { StoreProvider } from "./store";
import { isInstalled } from "./helpers/device";
import TabbedRoutes from "./TabbedRoutes";
import Auth from "./Auth";
Expand All @@ -40,7 +39,7 @@ export default function App() {
return (
<ConfigProvider>
<AppContextProvider>
<Provider store={store}>
<StoreProvider>
<GlobalStyles>
<BeforeInstallPromptProvider>
<UpdateContextProvider>
Expand All @@ -56,7 +55,7 @@ export default function App() {
</UpdateContextProvider>
</BeforeInstallPromptProvider>
</GlobalStyles>
</Provider>
</StoreProvider>
</AppContextProvider>
</ConfigProvider>
);
Expand Down
17 changes: 3 additions & 14 deletions src/TabbedRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,14 @@ import {
import PostDetail from "./pages/posts/PostPage";
import CommunitiesPage from "./pages/posts/CommunitiesPage";
import CommunityPage from "./pages/shared/CommunityPage";
import { useAppDispatch, useAppSelector } from "./store";
import {
handleSelector,
jwtIssSelector,
jwtSelector,
} from "./features/auth/authSlice";
import { useAppSelector } from "./store";
import { jwtIssSelector, jwtSelector } from "./features/auth/authSlice";
import ActorRedirect from "./ActorRedirect";
import SpecialFeedPage from "./pages/shared/SpecialFeedPage";
import styled from "@emotion/styled";
import UserPage from "./pages/profile/UserPage";
import SettingsPage from "./pages/settings/SettingsPage";
import { useContext, useEffect, useRef } from "react";
import { useContext, useRef } from "react";
import { AppContext } from "./features/auth/AppContext";
import InstallAppPage from "./pages/settings/InstallAppPage";
import SearchPage, { focusSearchBar } from "./pages/search/SearchPage";
Expand All @@ -57,7 +53,6 @@ import ProfilePage from "./pages/profile/ProfilePage";
import ProfileFeedHiddenPostsPage from "./pages/profile/ProfileFeedHiddenPostsPage";
import { PageContextProvider } from "./features/auth/PageContext";
import { scrollUpIfNeeded } from "./helpers/scrollUpIfNeeded";
import { getFavoriteCommunities } from "./features/community/communitySlice";
import BlocksSettingsPage from "./pages/settings/BlocksSettingsPage";
import { getDefaultServer } from "./services/app";

Expand All @@ -75,8 +70,6 @@ export default function TabbedRoutes() {
const totalUnread = useAppSelector(totalUnreadSelector);
const { status: updateStatus } = useContext(UpdateContext);
const shouldInstall = useShouldInstall();
const dispatch = useAppDispatch();
const activeHandle = useAppSelector(handleSelector);

const settingsNotificationCount =
(shouldInstall ? 1 : 0) + (updateStatus === "outdated" ? 1 : 0);
Expand All @@ -94,10 +87,6 @@ export default function TabbedRoutes() {
const isProfileButtonDisabled = location.pathname.startsWith("/profile");
const isSearchButtonDisabled = location.pathname.startsWith("/search");

useEffect(() => {
dispatch(getFavoriteCommunities());
}, [dispatch, activeHandle]);

async function onPostsClick() {
if (!isPostsButtonDisabled) return;

Expand Down
23 changes: 16 additions & 7 deletions src/features/community/communitySlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,22 @@ export const getFavoriteCommunities =
() => async (dispatch: AppDispatch, getState: () => RootState) => {
const userHandle = getState().auth.accountData?.activeHandle;

if (!userHandle) return;

const communities = await db.getSetting("favorite_communities", {
user_handle: userHandle,
});

dispatch(setFavorites(communities));
if (!userHandle) {
dispatch(setFavorites([]));
return;
}

try {
const communities = await db.getSetting("favorite_communities", {
user_handle: userHandle,
});

dispatch(setFavorites(communities));
} catch (e) {
dispatch(setFavorites([]));

// swallow the error, probably "Setting not found"
}
};

export const followCommunity =
Expand Down
33 changes: 0 additions & 33 deletions src/store.ts

This file was deleted.

62 changes: 62 additions & 0 deletions src/store.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { ReactNode, useEffect } from "react";
import { configureStore } from "@reduxjs/toolkit";
import postSlice from "./features/post/postSlice";
import {
Provider,
TypedUseSelectorHook,
useDispatch,
useSelector,
} from "react-redux";
import authSlice, { handleSelector } from "./features/auth/authSlice";
import commentSlice from "./features/comment/commentSlice";
import communitySlice, {
getFavoriteCommunities,
} from "./features/community/communitySlice";
import userSlice from "./features/user/userSlice";
import inboxSlice from "./features/inbox/inboxSlice";
import appearanceSlice, {
fetchSettingsFromDatabase,
} from "./features/settings/appearance/appearanceSlice";

const store = configureStore({
reducer: {
post: postSlice,
comment: commentSlice,
auth: authSlice,
community: communitySlice,
user: userSlice,
inbox: inboxSlice,
appearance: appearanceSlice,
},
});
export type RootState = ReturnType<typeof store.getState>;

export type AppDispatch = typeof store.dispatch;
export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

export default store;

let lastActiveHandle: string | undefined = undefined;
const activeHandleChange = () => {
const state = store.getState();
const activeHandle = handleSelector(state);

if (activeHandle !== lastActiveHandle) {
store.dispatch(getFavoriteCommunities());
lastActiveHandle = activeHandle;
}
};

export function StoreProvider({ children }: { children: ReactNode }) {
useEffect(() => {
// Load settings from DB into the store
store.dispatch(fetchSettingsFromDatabase());

// Subscribe to actions to handle handle changes, this can be used to react to other changes as well
// to coordinate side effects between slices.
store.subscribe(activeHandleChange);
}, []);

return <Provider store={store}>{children}</Provider>;
}

0 comments on commit fc1aba1

Please sign in to comment.