Skip to content

chore(angular-react): Migrate SettingsComponent to React#6

Open
devin-ai-integration[bot] wants to merge 5 commits intomainfrom
devin/1776107263-angular-to-react-settings
Open

chore(angular-react): Migrate SettingsComponent to React#6
devin-ai-integration[bot] wants to merge 5 commits intomainfrom
devin/1776107263-angular-to-react-settings

Conversation

@devin-ai-integration
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot commented Apr 13, 2026

Summary

Adds a React functional component (SettingsComponent.tsx) as a 1:1 port of the existing Angular SettingsComponent. The Angular component is not removed. This is an additive-only change — no existing files are modified.

Migration mapping:

  • Reactive FormGroup with formControlNameuseState controlled inputs with onChange
  • (ngSubmit)onSubmit handler
  • Angular signals (errors(), isSubmitting()) → useState
  • UserService / Router / DestroyRef injection → props (getCurrentUser, updateUser, onLogout, onNavigateToProfile)
  • ngOnInit form patching → useEffect with initialized ref guard (runs once on mount)
  • takeUntilDestroyed(this.destroyRef)mountedRef pattern to cancel in-flight async on unmount
  • ListErrorsComponent → inline stub (marked TODO) with defensive || {} guard matching Angular original

Updates since last revision

Five bugs identified by Devin Review have been addressed:

  1. useEffect re-render guard — Added initialized ref so the ngOnInit-equivalent effect runs exactly once on mount, preventing parent re-renders from resetting form fields (lines 66–88). getCurrentUser remains in the deps array to satisfy exhaustive-deps.
  2. Unmount cancellation — Added mountedRef to guard .then() / .catch() callbacks in handleSubmit (lines 67, 70–75, 97, 101). Prevents onNavigateToProfile from firing after the component has unmounted, matching Angular's takeUntilDestroyed(this.destroyRef).
  3. Defensive error guardListErrors now uses errors.errors || {} (line 42) to handle unexpected error shapes without crashing, matching the Angular original's errorList.errors || {} pattern.
  4. Prettier formatting — File formatted with the repo's .prettierrc config (arrowParens: "avoid", printWidth: 120, trailingComma: "all") as required by CLAUDE.md.
  5. StrictMode mountedRef fix — The mount-tracking effect now explicitly sets mountedRef.current = true in the effect body (line 71). Without this, React 18 StrictMode's mount → cleanup → re-mount cycle leaves mountedRef permanently false, causing both .then() and .catch() callbacks in handleSubmit to silently bail out — no navigation on success, no error display on failure.

Review & Testing Checklist for Human

  • React is not a project dependency. This Angular repo has no react/react-dom in package.json and no TSX config in tsconfig.json. The file will not compile without additional setup. Confirm this is intentional for this migration phase.
  • Empty password always sent (line 95): password state defaults to '' and is always included in the updateUser payload. Depending on the backend, this could unintentionally clear the user's password. The Angular version only sends password when the form control is dirty — this distinction is lost here.
  • isSubmitting not reset on success path (lines 91–105): On successful update, the component navigates away but never calls setIsSubmitting(false). If navigation is slow or fails, the form stays permanently disabled.
  • initialized ref guard vs. empty deps: The init effect uses a ref guard + [getCurrentUser] deps rather than []. This works but is unconventional — verify the ref guard correctly prevents re-initialization if getCurrentUser reference changes.

Suggested test plan: Add react and react-dom as dev dependencies, render <SettingsComponent> in a test harness with mock props, and verify: (1) form populates from getCurrentUser exactly once, (2) submit sends correct payload including only non-empty password, (3) error state renders ListErrors including with malformed error objects, (4) logout button fires callback, (5) unmounting during an in-flight updateUser does not trigger navigation, (6) form submission works correctly under React 18 StrictMode.

Notes

  • Part of a batch Angular-to-React migration across 7 repos.
  • The inline ListErrors component is a placeholder — should be replaced with the actual shared component once migrated.
  • CSS class names match the RealWorld Conduit global stylesheet; no component-level styles are imported.

Link to Devin session: https://app.devin.ai/sessions/885a7571c31c498d8aeb31891081a88e
Requested by: @lburgers


Open with Devin

feat: port logic from Angular to React
feat: translate template to JSX
feat: wire up inputs, events, and dependencies

Migrates SettingsComponent from Angular to React:
- Reactive FormGroup → useState controlled inputs
- formControlName → value + onChange
- (ngSubmit) → onSubmit
- Angular signals (errors(), isSubmitting()) → useState
- UserService injection → props (getCurrentUser, updateUser, onLogout)
- Router.navigate → onNavigateToProfile callback
- DestroyRef + takeUntilDestroyed → component unmount (no extra cleanup needed)
- ListErrorsComponent → inline ListErrors placeholder (TODO)

Co-Authored-By: Lukas Burger <lukaskburger@gmail.com>
@devin-ai-integration
Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

devin-ai-integration[bot]

This comment was marked as resolved.

Added initialized ref guard so the form initialization runs exactly
once on mount, matching Angular's ngOnInit semantics. Without this,
unmemoized getCurrentUser prop would cause the effect to re-run on
every parent render, wiping in-progress user edits.

Co-Authored-By: Lukas Burger <lukaskburger@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

1. ListErrors now guards against undefined errors.errors with || {},
   matching Angular's errorList.errors || {} pattern.
2. Added mountedRef to prevent onNavigateToProfile from firing after
   unmount, matching Angular's takeUntilDestroyed(this.destroyRef).

Co-Authored-By: Lukas Burger <lukaskburger@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

Co-Authored-By: Lukas Burger <lukaskburger@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

React 18 StrictMode double-invokes effects (mount → cleanup → mount).
Without resetting mountedRef to true in the effect body, the ref stays
false after the first cleanup, causing handleSubmit callbacks to bail
out silently.

Co-Authored-By: Lukas Burger <lukaskburger@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant