Project

General

Profile

Actions

Bug #22381

open

Replace redux-form

Added by Lisa Knox over 1 year ago. Updated 6 days ago.

Status:
In Progress
Priority:
Normal
Assigned To:
Category:
Workbench2
Target version:
Story points:
-

Description

The The primary goal of this issue is to remove errors that appear in the browser console when using workbench. The redux-form library is outdated and throw multiple console warnings whenever a form using it is used in workbench. We already use an alternative for some of our forms, provided by MUI, although it may not cover all use cases:
https://mui.com/material-ui/react-dialog/#form-dialogs

Other options include Formik and React Hook Form:
https://formik.org/
https://react-hook-form.com/

The primary performance drawback to redux-form is that it stores every bit of form state in the redux store. The Modern view on this is that form state, with a few exceptions, should be managed from within the form component, keeping the data closer to where it is relevant and favoring composition.

Some other reasons for replacing redux-form:
  • Performance Issues: Because redux-form stores the entire form state in the Redux store, any state change (e.g., typing into a field) triggers a Redux action and updates the global store, potentially causing unnecessary re-renders.
  • Complexity: It adds unnecessary complexity often requires more boilerplate compared to alternatives, making the code harder to read and maintain.
  • Debugging Overhead: The increased number of Redux actions can clutter debugging tools like Redux DevTools, making it harder to isolate issues.
  • Alternatives Offer Better Features, such as:
    • Better Performance
    • Simplicity
    • Integration with Modern Features, such as React Hooks
    • Better Developer Experience: More concise APIs, better documentation, and larger active communities.

A cursory search of Workbench shows that redux-form is used in 125 files.


Subtasks 1 (1 open0 closed)

Task #23370: Review 22381-redux-form-refactorIn ProgressStephen Smith03/18/2026Actions

Related issues 2 (1 open1 closed)

Related to Arvados - Bug #22231: Clean up MUI and react warnings/errors that appear on the browser consoleResolvedLisa KnoxActions
Related to Arvados - Bug #22379: Refactor Virtualized listsNewLisa KnoxActions
Actions #1

Updated by Lisa Knox over 1 year ago

  • Related to Bug #22231: Clean up MUI and react warnings/errors that appear on the browser console added
Actions #2

Updated by Brett Smith 3 months ago

  • Target version set to Development 2026-01-06
  • Assigned To set to Lisa Knox
Actions #3

Updated by Brett Smith 3 months ago

Plan is to do a little initial development, then propose one alternative library, and get agreement with Stephen before continuing with the bulk of development.

If it makes development substantially easier, I am open to UI changes as part of this branch—especially minor changes like spacing or button dimensions—but they should get interface-reviewed as normal.

Actions #4

Updated by Brett Smith 3 months ago

  • Related to Bug #22379: Refactor Virtualized lists added
Actions #5

Updated by Brett Smith 3 months ago

  • Subtask #23370 added
Actions #6

Updated by Lisa Knox 3 months ago

  • Status changed from New to In Progress

It was decided in discussion with Stephen that we should convert all of our redux-form forms to use the MUI equivalent. We use other MUI components extensively and already have several of our forms built with MUI. It is preferable to have all of our forms built using the same library, and any resulting UI changes will likely bring the forms more in line with the rest of our UI.

Actions #7

Updated by Brett Smith 3 months ago

  • Target version changed from Development 2026-01-06 to Development 2026-01-21
Actions #8

Updated by Lisa Knox 2 months ago

As this ticket is huge, review will be done in stages. Note that intermediate stages may not pass tests.

22381-redux-form-refactor @ 0596ca8629dc153807aaba369192195d7af82e70

developer-run-tests: #5010

Actions #9

Updated by Stephen Smith 2 months ago

Overall looks good! Here's a few suggestions:

  • In multiselect-actions, if you filter out undefined results in getResourcesFromCheckedList like so:
.filter((resource): resource is GroupContentsResource => !!resource)

You can avoid having to deal with undefined everywhere that uses it, you can get rid of .filter(res => !!res) in openCollectionCopy and you shouldn't need the ! in the .map

  • In collection-copy-actions.ts I noticed that copyCollection catches some errors to show a toast but passes through others to be handled by the caller, I think it would be better to consolidate that by removing the catch block from copyCollection so that all errors end up in the copySingleCollection catch block to handle the UNIQUE_NAME_VIOLATION as well as unknown errors. I have a slight preference for moving the error handling up so that copyCollection is more reusable. This can apply to any other area where the error handling got split up
  • In workbench actions copyCollectionRunner and moveCollectionRunner, it would be ideal to group the result toasts - we can probably make a separate ticket but if you're up for it, I previously made a helper to show grouped result toasts showGroupedCommonResourceResultSnackbars used in toggleResourceTrashed - "all" you have to do is map each item to a promise that returns the result of the service action (to resolve the promise to the resource) and hand the helper the settled promises and a map of resource errors to functions that generates the appropriate message. You can .then. off of that and do anything else needed with the results or updated resources.
  • isfileOperationLocation It might be good to also validate uuid.length and subpath.length just in case it's possible to get an object with empty string fields somehow
  • dialog-collection-partial-copy-to-existing-collection.tsx I'm wondering about the currentUuids and if there's any reason to pass an array containing an empty string vs just an empty array when destination.uuid isn't set
Actions #10

Updated by Brett Smith 2 months ago

  • Target version changed from Development 2026-01-21 to Development 2026-02-04
Actions #11

Updated by Brett Smith about 2 months ago

  • Target version changed from Development 2026-02-04 to Development 2026-02-18
Actions #12

Updated by Brett Smith about 1 month ago

  • Target version changed from Development 2026-02-18 to Development 2026-03-04
Actions #13

Updated by Brett Smith 20 days ago

  • Target version changed from Development 2026-03-04 to Development 2026-03-18
Actions #14

Updated by Lisa Knox 20 days ago

22381-redux-form-refactor @ 1de181bebba16926d98808cfbc19e493b8e6cdcb

Intermediate review of in a not-completely-working state. The project and user profile tests don't pass, and I only have two of the suggestions from the previous review implemented.

Actions #15

Updated by Stephen Smith 14 days ago · Edited

Overall looking good, here's a couple things I saw that I think could be improved:

  • In resource-properties-form, it seems like an anti-pattern to send signals between neighboring components using state setters, I have an alternate suggestion:
    • The purpose seems to be to allow the Key field when selected and the Add button when pressed to clear the value field
    • An annoying factor is that the value field and the form have their own copies of the value, but this makes sense to encapsulate the validation
    • There are 2 cases where the signal is triggered
      • Key field onSelect
      • Add button submission
      • In both, we are setting the parent field component's value to undefined (at least in the Add button handler it does. When the key field is onSelected, the value field clears itself but doesn't send the updated value to the parent). If both send undefined to the parent, we could have the value field react to the parent field being set to undefined and not need the extra signal.
    • You would just need to create a handleSetKey(key) that sets the key as well as setCurrentValue to undefined like handleAddProperty and change the onFocus handler inside the Key component to call onSelect with undefined to update the parent component instead of sending a signal.
    • Then, instead of passing the signal to the value component, pass the currentValue and check for it being undefined in the useEffect.
  • When it comes to using isSubmitting to keep track of submitting state, it seems complicated to use useEffect to detect when submission is done by examining the dialog close state and form error state.
    • I would suggest something more watertight, like chaining .finally() off of the updateFn / moveProjects / whatever dispatchable action is being done. The caveat is that Dispatch apparently doesn't know about async thunks, so you'll need to change the prop type of those mapDispatch to Promise<void> or whatver it's supposed to return in order for the types to understand what's going on - this is kind of a cast since dispatch returns any but at least the prop type for the mapped dispatch will be setting the correct Promise return type.
  • The CircularSuspense component seems a bit overengineered for solving the problem of showing a loading indicator, but I'm less inclined to complain since it's self contained. It's unfortunate that only later MUI versions have the loading prop on buttons, which I think shows a loading indicator on a disabled button like redux forms does. I would have gone for something simpler that perhaps uses visibility:hidden and absolute positioning on the indicator to avoid layout shift instead of using a useLayoutEffect and js calculated sizing. Also that file uses tabs for some reason.
Actions #16

Updated by Lisa Knox 6 days ago

22381-redux-form-refactor @ ef194bd6aa0730e2cfe323b6c06897950e2b4dea

developer-run-tests: #5055

  • In collection-copy-actions.ts I noticed that copyCollection catches some errors to show a toast...

Fixed

  • In workbench actions copyCollectionRunner and moveCollectionRunner, it would be ideal to group the result toasts - we can probably make a separate ticket but if you're up for it.

This is enough work and isolated enough that I believe it should be on its own ticket.

  • isfileOperationLocation It might be good to also validate uuid.length and subpath.length...

done

  • dialog-collection-partial-copy-to-existing-collection.tsx I'm wondering about the currentUuids...

You're right, fixed

  • In resource-properties-form, it seems like an anti-pattern to send signals between neighboring components using state setters...

When I write that I had Go channels in mind, wishing javascript could be more like Go. That said, injecting a pattern from another language just because I think it's cool is not good coding practice, so I've removed in favor of the more traditional approach you recommended.

  • When it comes to using isSubmitting to keep track of submitting state, it seems complicated to use useEffect to detect when submission is done...

I'm going to push back here because the proposed solution seems more complicated than the existing solution. It feels simpler to me to have a simple if/then (in the useEffect), and by handling it within the component, managing the disabled/spinner state on the form submit button gets very easy.

  • The CircularSuspense component seems a bit overengineered for solving the problem of showing a loading indicator, but I'm less inclined to complain since it's self contained...

Part of the motivation for this refactor was to clear a blocker on #22379, for which the proposed solution includes upgrading MUI to take advantage of the virtualized list support in later MUI versions. By isolating and generalizing CircularSuspense, it will be trivial to drop in a replacement once that MUI upgrade happens.

Actions

Also available in: Atom PDF