Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove use of useActions #3911

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Remove use of useActions #3911

wants to merge 2 commits into from

Conversation

joel-jeremy
Copy link
Contributor

No description provided.

@actual-github-bot actual-github-bot bot changed the title Remove use of useActions [WIP] Remove use of useActions Nov 27, 2024
Copy link

netlify bot commented Nov 27, 2024

Deploy Preview for actualbudget ready!

Name Link
🔨 Latest commit b514751
🔍 Latest deploy log https://app.netlify.com/sites/actualbudget/deploys/67474802b61a4d000810bb3b
😎 Deploy Preview https://deploy-preview-3911.demo.actualbudget.org
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@joel-jeremy joel-jeremy changed the title [WIP] Remove use of useActions Remove use of useActions Nov 27, 2024
Copy link
Contributor

Bundle Stats — desktop-client

Hey there, this message comes from a GitHub action that helps you and reviewers to understand how these changes affect the size of this project's bundle.

As this PR is updated, I'll keep you updated on how the bundle size is impacted.

Total

Files count Total bundle size % Changed
10 5.45 MB → 5.45 MB (+242 B) +0.00%
Changeset
File Δ Size
src/components/LoggedInUser.tsx 📈 +126 B (+4.52%) 2.72 kB → 2.85 kB
src/components/UpdateNotification.tsx 📈 +53 B (+1.47%) 3.53 kB → 3.58 kB
src/components/settings/index.tsx 📈 +70 B (+1.12%) 6.13 kB → 6.2 kB
src/components/Titlebar.tsx 📈 +50 B (+0.61%) 8.02 kB → 8.07 kB
src/components/manager/WelcomeScreen.tsx 📈 +12 B (+0.29%) 4.05 kB → 4.06 kB
src/components/settings/Reset.tsx 📈 +6 B (+0.26%) 2.24 kB → 2.25 kB
src/components/manager/ConfigServer.tsx 📈 +4 B (+0.05%) 7.16 kB → 7.16 kB
src/components/modals/ImportTransactionsModal/ImportTransactionsModal.jsx 📉 -79 B (-0.26%) 30.12 kB → 30.04 kB
View detailed bundle breakdown

Added

No assets were added

Removed

No assets were removed

Bigger

Asset File Size % Changed
static/js/wide.js 241.19 kB → 241.36 kB (+173 B) +0.07%
static/js/index.js 3.44 MB → 3.44 MB (+69 B) +0.00%

Smaller

No assets were smaller

Unchanged

Asset File Size % Changed
static/js/indexeddb-main-thread-worker-e59fee74.js 13.5 kB 0%
static/js/workbox-window.prod.es5.js 5.69 kB 0%
static/js/useAccountPreviewTransactions.js 1.68 kB 0%
static/js/resize-observer.js 18.37 kB 0%
static/js/BackgroundImage.js 122.29 kB 0%
static/js/narrow.js 82.93 kB 0%
static/js/AppliedFilters.js 21.32 kB 0%
static/js/ReportRouter.js 1.52 MB 0%

Copy link
Contributor

Bundle Stats — loot-core

Hey there, this message comes from a GitHub action that helps you and reviewers to understand how these changes affect the size of this project's bundle.

As this PR is updated, I'll keep you updated on how the bundle size is impacted.

Total

Files count Total bundle size % Changed
1 1.32 MB 0%

Changeset

No files were changed

View detailed bundle breakdown

Added

No assets were added

Removed

No assets were removed

Bigger

No assets were bigger

Smaller

No assets were smaller

Unchanged

Asset File Size % Changed
kcab.worker.js 1.32 MB 0%

Copy link
Contributor

coderabbitai bot commented Nov 27, 2024

Walkthrough

The pull request introduces significant changes across multiple components in the desktop client application, transitioning from a custom useActions hook to the Redux useDispatch hook for action dispatching. This change affects the LoggedInUser, Titlebar, UpdateNotification, ConfigServer, WelcomeScreen, ImportTransactionsModal, Reset, and Settings components. Each component has been updated to directly dispatch actions such as getUserData, signOut, sync, updateApp, createBudget, and resetSync. The modifications include the removal of the useActions hook and the implementation of local functions that utilize dispatch for invoking actions. The updates streamline the action dispatching process, enhance clarity, and align with Redux best practices. Error handling logic remains largely unchanged, but the manner of invoking actions has been standardized across components. Overall, the changes improve the integration of Redux within the application, ensuring a consistent approach to state management.

Possibly related PRs

Suggested labels

:sparkles: Merged

Suggested reviewers

  • MikesGlitch
  • youngcw

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 eslint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

packages/desktop-client/src/components/LoggedInUser.tsx

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "eslint-plugin-eslint-plugin".

(The package "eslint-plugin-eslint-plugin" was not found when loaded as a Node module from the directory "/packages/eslint-plugin-actual".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-eslint-plugin@latest --save-dev

The plugin "eslint-plugin-eslint-plugin" was referenced from the config file in "packages/eslint-plugin-actual/.eslintrc.js".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (11)
packages/desktop-client/src/components/settings/Reset.tsx (1)

45-45: Consider adding TypeScript type for dispatch

The Redux integration looks good! For better type safety, consider explicitly typing the dispatch:

- const dispatch = useDispatch();
+ const dispatch = useDispatch<AppDispatch>();

This would require importing AppDispatch from your store configuration:

import { AppDispatch } from 'path/to/store';

Also applies to: 51-51

packages/desktop-client/src/components/UpdateNotification.tsx (3)

23-26: Consider memoizing the callback function

While the transition to useDispatch is good, consider memoizing the onRestart callback using useCallback to prevent unnecessary re-renders in child components that receive this as a prop.

  const dispatch = useDispatch();
- const onRestart = () => {
+ const onRestart = useCallback(() => {
    dispatch(updateApp());
- };
+ }, [dispatch]);

87-92: Enhance the comment documentation

While the state update logic is correct, consider improving the comment to better explain why we need to persist this flag for the entire session and its implications.

-  // Set a flag to never show an update notification again for this session
+  // Prevent update notifications from reappearing during this session to avoid
+  // repeatedly interrupting the user after they've dismissed it once

Line range hint 1-108: Consider splitting presentation and container components

The component currently handles both state management and presentation. Consider splitting it into:

  1. A container component handling Redux state and actions
  2. A presentational component focusing on the UI

This would improve maintainability and make the component more testable.

Example structure:

// UpdateNotificationContainer.tsx
export function UpdateNotificationContainer() {
  const dispatch = useDispatch();
  const updateInfo = useSelector((state: State) => state.app.updateInfo);
  // ... other hooks and handlers ...
  
  return <UpdateNotificationPresentation 
    updateInfo={updateInfo}
    onRestart={onRestart}
    onClose={() => dispatch(setAppState({...}))}
  />;
}

// UpdateNotificationPresentation.tsx
export function UpdateNotificationPresentation({ 
  updateInfo, 
  onRestart, 
  onClose 
}: Props) {
  // Pure presentation logic
}
packages/desktop-client/src/components/LoggedInUser.tsx (3)

37-41: Consider adding error handling to the initialization

While the async initialization is well-structured, it would be beneficial to handle potential errors during getUserData dispatch.

 async function init() {
-  await dispatch(getUserData());
+  try {
+    await dispatch(getUserData());
+  } catch (error) {
+    console.error('Failed to get user data:', error);
+    // Optionally show user-friendly error message
+  }
 }

44-46: LGTM! Consider adding type safety to onMenuSelect parameter

The action dispatches are well-implemented and properly handle async operations. One small improvement would be to add type safety to the menu selection handler.

- async function onMenuSelect(type) {
+ type MenuAction = 'change-password' | 'sign-in' | 'sign-out' | 'config-server';
+ async function onMenuSelect(type: MenuAction) {

Also applies to: 49-49, 61-61, 65-65, 68-68


useActions hook is still in use and needs attention

  • packages/desktop-client/src/hooks/useActions.ts: The hook itself still exists
  • packages/desktop-client/src/components/accounts/Account.tsx: Active usage of the hook
  • Two files still importing the type: index.tsx and global-events.ts

This component has successfully removed useActions, but there are remaining instances in the codebase that need to be addressed for complete migration.

🔗 Analysis chain

Line range hint 1-141: Verify complete removal of useActions

Let's ensure no traces of useActions remain in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining useActions usage in the codebase
rg "useActions" packages/desktop-client/src/

Length of output: 788

packages/desktop-client/src/components/settings/index.tsx (1)

137-143: Consider memoizing the loadPrefs dispatch

While the current implementation is functional, consider memoizing the loadPrefs dispatch to optimize performance:

+ const memoizedLoadPrefs = useCallback(() => {
+   dispatch(loadPrefs());
+ }, [dispatch]);

  useEffect(() => {
-   const unlisten = listen('prefs-updated', () => {
-     dispatch(loadPrefs());
-   });
+   const unlisten = listen('prefs-updated', memoizedLoadPrefs);

-   dispatch(loadPrefs());
+   memoizedLoadPrefs();
    return () => unlisten();
-  }, [dispatch]);
+  }, [memoizedLoadPrefs]);

This change would:

  • Prevent unnecessary re-creation of the callback on each render
  • Maintain consistent reference for the event listener
  • Follow React's optimization patterns for callbacks
packages/desktop-client/src/components/Titlebar.tsx (1)

196-206: Consider using useCallback to memoize onSync

Wrapping onSync with useCallback will prevent unnecessary re-creation of the function on each render. This optimization is beneficial since onSync is used in the dependency array of useHotkeys and passed to the Button component.

Apply this diff:

+import { useCallback } from 'react';
...
-const onSync = () => dispatch(sync());
+const onSync = useCallback(() => dispatch(sync()), [dispatch]);
packages/desktop-client/src/components/modals/ImportTransactionsModal/ImportTransactionsModal.jsx (2)

312-312: Consider excluding dispatch from dependency arrays

Including dispatch in the dependency array of useCallback hooks is generally unnecessary because dispatch is stable and doesn't change between renders. Excluding it can prevent unnecessary re-creations of the callback.


403-403: Consider excluding dispatch from dependency arrays

Similarly, you can remove dispatch from the dependency array in this useCallback hook to avoid unnecessary re-creations.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 22623ce and b514751.

⛔ Files ignored due to path filters (1)
  • upcoming-release-notes/3911.md is excluded by !**/*.md
📒 Files selected for processing (8)
  • packages/desktop-client/src/components/LoggedInUser.tsx (3 hunks)
  • packages/desktop-client/src/components/Titlebar.tsx (4 hunks)
  • packages/desktop-client/src/components/UpdateNotification.tsx (4 hunks)
  • packages/desktop-client/src/components/manager/ConfigServer.tsx (4 hunks)
  • packages/desktop-client/src/components/manager/WelcomeScreen.tsx (4 hunks)
  • packages/desktop-client/src/components/modals/ImportTransactionsModal/ImportTransactionsModal.jsx (7 hunks)
  • packages/desktop-client/src/components/settings/Reset.tsx (2 hunks)
  • packages/desktop-client/src/components/settings/index.tsx (3 hunks)
🔇 Additional comments (21)
packages/desktop-client/src/components/settings/Reset.tsx (1)

2-2: LGTM! Import changes align with Redux integration

The new imports correctly support the transition from useActions to Redux's useDispatch pattern.

Also applies to: 6-6

packages/desktop-client/src/components/manager/WelcomeScreen.tsx (3)

3-5: LGTM: Clean import organization

The new imports follow Redux best practices by directly importing the dispatch hook and actions.


16-16: LGTM: Proper Redux hook usage

The useDispatch hook is correctly implemented at the component level, aligning with Redux best practices.


82-82: LGTM: Clean action dispatch implementation

The button handlers have been correctly updated to use dispatch, maintaining the same functionality while following Redux patterns.

Let's verify that all useActions occurrences have been removed from this component:

Also applies to: 92-92, 95-99

✅ Verification successful

Verified: All useActions have been properly replaced with useDispatch

The component has been correctly migrated:

  • No instances of useActions remain in the file
  • useDispatch is properly imported and used
  • All button handlers correctly use dispatch for actions
  • The functionality remains equivalent with the new implementation
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify no remaining useActions usage in this component
rg "useActions" "packages/desktop-client/src/components/manager/WelcomeScreen.tsx"

Length of output: 80


Script:

#!/bin/bash
# Let's verify the component's imports and usage patterns more thoroughly
cat "packages/desktop-client/src/components/manager/WelcomeScreen.tsx"

Length of output: 3339

packages/desktop-client/src/components/UpdateNotification.tsx (1)

3-3: LGTM! Clean import organization

The imports are well-organized and correctly transition from useActions to Redux's useDispatch, aligning with Redux best practices.

Also applies to: 5-5

packages/desktop-client/src/components/LoggedInUser.tsx (2)

4-4: LGTM! Clean Redux setup

The migration to direct Redux hooks and action imports follows best practices and improves code clarity.

Also applies to: 6-6


29-31: LGTM! Proper Redux hook usage

The dispatch hook is correctly initialized alongside the existing selector, maintaining component functionality while modernizing the implementation.

packages/desktop-client/src/components/settings/index.tsx (4)

2-2: LGTM: Clean migration to useDispatch

The addition of useDispatch import aligns with Redux best practices and the PR's objective to remove useActions.


7-7: LGTM: Direct action imports

Clean transition to importing actions directly, which is consistent with standard Redux patterns.


130-134: LGTM: Clean dispatch implementation

The dispatch initialization and handler implementation follow React best practices:

  • Proper hook usage with useDispatch
  • Clean handler wrapping for the closeBudget action

176-176: LGTM: Clean event handler binding

The Button correctly uses the new onCloseBudget handler, maintaining consistency with the dispatch pattern.

packages/desktop-client/src/components/manager/ConfigServer.tsx (4)

4-4: LGTM: Clean import changes for Redux migration

The import changes appropriately set up direct usage of Redux's useDispatch and action creators, aligning with the PR objective of removing useActions.

Also applies to: 6-6


26-26: LGTM: Proper Redux hook initialization

The useDispatch hook is correctly initialized at the component's top level, following Redux best practices.


81-81: LGTM: Proper Redux dispatch implementation

The transition to using dispatch is implemented correctly, maintaining the async/await pattern and proper action dispatching.

Also applies to: 108-108, 114-114


Line range hint 1-238: Verify complete removal of useActions

Let's verify that no instances of useActions remain in this file or related components.

✅ Verification successful

No instances of useActions found in ConfigServer.tsx

The file correctly uses useDispatch from react-redux and imports specific action creators (createBudget, loggedIn, signOut) from 'loot-core/client/actions'. There are no remaining instances of useActions in this file.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining useActions usage in the codebase
rg "useActions" --type ts --type tsx

# Search for any remaining imports from the actions file that might still use the old pattern
rg "from ['|\"].*actions['|\"]" --type ts --type tsx

Length of output: 151


Script:

#!/bin/bash
# Search for any remaining useActions usage in the file and related components
rg "useActions" "packages/desktop-client/src/components/manager/ConfigServer.tsx"

# Search for any remaining imports from actions in the file
rg "from ['\"].*actions['\"]" "packages/desktop-client/src/components/manager/ConfigServer.tsx"

Length of output: 255

packages/desktop-client/src/components/Titlebar.tsx (4)

3-3: LGTM!

Importing useDispatch from 'react-redux' is appropriate.


9-9: LGTM!

Importing the sync action from 'loot-core/client/actions' is correct.


112-112: LGTM!

Initializing dispatch using useDispatch() is appropriate.


228-228: LGTM!

Updating the onPress handler to use onSync is appropriate and aligns with the changes made.

packages/desktop-client/src/components/modals/ImportTransactionsModal/ImportTransactionsModal.jsx (2)

268-268: Ensure dispatched actions return promises when using await

When you use await dispatch(action), it assumes that the dispatched action returns a promise. Please verify that importPreviewTransactions returns a promise when dispatched. If it doesn't, the await keyword may not behave as expected.

Run the following script to confirm if importPreviewTransactions returns a promise:

✅ Verification successful

importPreviewTransactions correctly returns a promise when dispatched

The action creator importPreviewTransactions returns an async thunk that explicitly declares its return type as Promise<boolean>. The implementation shows it's using async/await syntax and returns a promise, making it safe to use with await dispatch(action).

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if 'importPreviewTransactions' returns a promise when dispatched

# Find the definition of 'importPreviewTransactions'
ast-grep --pattern $'export function importPreviewTransactions($_, $_) {
  $$$
}'

# Look for 'async' keyword or promise return statements in the function definition
rg -A 5 'export function importPreviewTransactions' | rg 'async|return.*Promise'

Length of output: 1810


323-325: Confirm that parseTransactions returns a promise when dispatched

Similarly, ensure that parseTransactions returns a promise when dispatched. Using await on a non-promise value won't have the intended effect.

Run the following script to verify if parseTransactions returns a promise:

✅ Verification successful

parseTransactions is correctly implemented to return a promise when dispatched

The implementation in packages/loot-core/src/client/actions/account.ts shows that parseTransactions returns a thunk that is an async function, which in turn returns the result of an awaited send operation. This pattern ensures that when dispatched, it will indeed return a promise, making the await usage in the modal component correct and effective.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if 'parseTransactions' returns a promise when dispatched

# Find the definition of 'parseTransactions'
ast-grep --pattern $'export function parseTransactions($_, $_) {
  $$$
}'

# Look for 'async' keyword or promise return statements in the function definition
rg -A 5 'export function parseTransactions' | rg 'async|return.*Promise'

Length of output: 820

Comment on lines +114 to 115
await dispatch(createBudget({ testMode: true }));
window.__navigate('/');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Inconsistent navigation approach detected

The code uses window.__navigate here while the rest of the component uses the useNavigate hook. Consider using the hook consistently:

-    window.__navigate('/');
+    navigate('/');

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +656 to +660
const didChange = await dispatch(
importTransactions(accountId, finalTransactions, reconcile),
);
if (didChange) {
await getPayees();
await dispatch(getPayees());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for dispatched actions

When dispatching importTransactions and getPayees, consider adding error handling to manage potential exceptions. This ensures that your application can handle failures gracefully.

Apply this diff to add error handling:

+try {
  const didChange = await dispatch(
    importTransactions(accountId, finalTransactions, reconcile),
  );
  if (didChange) {
    await dispatch(getPayees());
  }
+} catch (error) {
+  // Handle the error appropriately
+  console.error('Error importing transactions:', error);
+  setError({ parsed: false, message: 'Failed to import transactions.' });
+  setLoadingState(null);
+}

Committable suggestion skipped: line range outside the PR's diff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant