refactor(core): convert MultiSchemaField AnyOfField from class to function component#5073
refactor(core): convert MultiSchemaField AnyOfField from class to function component#5073Copilot wants to merge 5 commits into
AnyOfField from class to function component#5073Conversation
… component Agent-Logs-Url: https://github.com/rjsf-team/react-jsonschema-form/sessions/f1f6acb8-3be3-48a3-8738-8e755400ab2c Co-authored-by: nickgros <17580037+nickgros@users.noreply.github.com>
…stive-deps lint rule Agent-Logs-Url: https://github.com/rjsf-team/react-jsonschema-form/sessions/f1f6acb8-3be3-48a3-8738-8e755400ab2c Co-authored-by: nickgros <17580037+nickgros@users.noreply.github.com>
…schemafield-to-function-component Co-authored-by: nickgros <17580037+nickgros@users.noreply.github.com>
| const [{ selectedOption, retrievedOptions }, setState] = useState<{ | ||
| selectedOption: number; | ||
| retrievedOptions: S[]; | ||
| }>(() => { |
There was a problem hiding this comment.
@copilot Either create a type for this (similar to the removed AnyOfFieldState), or split this state into two atoms. Also, consider if using a reducer is appropriate.
Consider the rules of hooks and "you might not need an effect". Are there better alternatives than using these refs and this useEffect?
There was a problem hiding this comment.
Done in febfd4a.
- Restored the
AnyOfFieldState<S>named type for the combined state. - Replaced
useEffect+ threeuseRefs with the React "adjusting state when a prop changes" pattern: threeuseStateatoms (prevOptions,prevFormData,prevFieldPathIdId) track previous prop values, and the derivation logic runs synchronously during render — nouseEffectneeded.currentRetrieved/currentSelectedlocals carry the up-to-date values through the rest of the render body.
…nder; restore AnyOfFieldState type Agent-Logs-Url: https://github.com/rjsf-team/react-jsonschema-form/sessions/ec7336ed-fc8e-4e27-9256-928995d3bd4a Co-authored-by: nickgros <17580037+nickgros@users.noreply.github.com>
|
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
| // Track previous prop values in state so we can derive state changes during render, | ||
| // avoiding the need for a useEffect + refs to replicate componentDidUpdate behaviour. |
There was a problem hiding this comment.
| // Track previous prop values in state so we can derive state changes during render, | |
| // avoiding the need for a useEffect + refs to replicate componentDidUpdate behaviour. | |
| // Track previous prop values in state so we can derive state changes during render |
| // avoiding the need for a useEffect + refs to replicate componentDidUpdate behaviour. | ||
| const [prevOptions, setPrevOptions] = useState(options); | ||
| const [prevFormData, setPrevFormData] = useState(formData); | ||
| const [prevFieldPathIdId, setPrevFieldPathIdId] = useState(fieldPathIdId); |
There was a problem hiding this comment.
@copilot This is a lot of connected state variables and it is hard to reason about changing them. Create a reducer function and use useReducer.
There was a problem hiding this comment.
Done in 35dad30.
All four connected state atoms are now managed by a single useReducer:
AnyOfFieldState<S>— expanded to includeprevOptions,prevFormData, andprevFieldPathIdIdalongsideselectedOptionandretrievedOptionsAnyOfFieldAction<S>— a discriminated union ofSYNC_PROPS(dispatched during render when tracked props change) andSELECT_OPTION(dispatched fromonOptionChange)anyOfFieldReducer<S>— a pure function defined outside the component;SYNC_PROPSsets all fields from the pre-computed action payload,SELECT_OPTIONupdates onlyselectedOptionandretrievedOptions
…OfFieldState/AnyOfFieldAction types Agent-Logs-Url: https://github.com/rjsf-team/react-jsonschema-form/sessions/4033026f-26f4-4a1d-9af6-374fd021900d Co-authored-by: nickgros <17580037+nickgros@users.noreply.github.com>
|
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
AnyOfFieldinMultiSchemaField.tsxwas the last remaining class component in the fields directory. This converts it to a function component following the same patterns used byBooleanField,ObjectField, andLayoutMultiSchemaField.Key changes
useReducerlazy initializer replaces the constructor; computesretrievedOptionsand initialselectedOptionin one pass on mount. All state is captured in a namedAnyOfFieldState<S>type.componentDidUpdate→ derived state during render — Previous prop values are stored inside the reducer state (prevOptions,prevFormData,prevFieldPathIdId). When a prop changes, updatedcurrentRetrieved/currentSelectedlocals are computed synchronously during render and a singleSYNC_PROPSaction is dispatched — nouseEffectoruseRefrequired. React re-renders immediately with the new state, preserving the original cascade ordering (options recomputed first, thenselectedOptionre-evaluated against the freshly retrieved options).useReducer— All connected state is managed by a singleanyOfFieldReducer<S>pure function defined outside the component, with a discriminatedAnyOfFieldAction<S>union (SYNC_PROPS|SELECT_OPTION) making every transition explicit and easy to reason about.onOptionChange— converted touseCallbackwith stable primitive deps; dispatchesSELECT_OPTION.getFieldId()— replaced by an inline computedfieldIdstring.fieldPathId.$idandfieldPathId.pathare extracted as primitive locals before hooks to avoid unnecessary callback re-runs from object reference churn.