-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Description
Hey team! I've been integrating @pipedream/connect-react
into our product and encountered several challenges with handling pre-configured props. I wanted to share what I found and the solutions that worked for us, in case this helps improve the library.
Our Use Case
Users can configure Pipedream component forms (e.g., Google Sheets actions, Slack messages) and save those configurations to database. Later, when trigger events happen, we execute those actions with the saved props. Users can also come back and edit their saved configurations, which means we need to:
- Store
configuredProps
from the form - Repopulate the form with those stored values when users want to edit
- Have everything work correctly with dynamic props, remote options, optional fields, etc.
This workflow revealed some unexpected behaviors that I wanted to document with potential fixes.
Issue 1: Pre-configured props don't load remote options 🔴
Impact: Critical - Forms don't work when editing saved configurations
What we observed:
When mounting <ComponentFormContainer>
with configuredProps
that include an app selection, dependent fields with remoteOptions
show empty dropdowns instead of fetching their options.
How to reproduce:
<ComponentFormContainer
component={{
key: 'google_sheets-update-row',
// ... other component props
}}
configuredProps={{
googleSheets: { authProvisionId: "apn_xxx" }
}}
externalUserId="test-user"
/>
Expected: Spreadsheet ID dropdown should fetch and show list of spreadsheets
Actual: Dropdown shows "No options"
Root cause:
In form-context.tsx
line 384, the queryDisabledIdx
initialization uses _configuredProps
(the empty internal state) instead of the actual configuredProps
parameter passed to the component. This causes all remote option queries to be blocked when mounting with pre-configured values.
Suggested fix:
// Current implementation:
useEffect(() => {
updateConfiguredPropsQueryDisabledIdx(_configuredProps)
}, [component.key]);
// Proposed change:
useEffect(() => {
updateConfiguredPropsQueryDisabledIdx(configuredProps)
}, [component.key]);
Issue 2: Optional props with values don't auto-enable 🔴
Impact: Critical - Saved data appears lost to users
What we observed:
When you save a form with optional fields filled in, then remount the form with those saved configuredProps
, the optional fields don't appear in the form - they stay hidden.
How to reproduce:
// User fills optional "Drive" field and saves
const saved = {
googleSheets: { authProvisionId: "apn_xxx" },
drive: "My Drive", // optional field with value
sheetId: { __lv: { label: "My Sheet", value: "sheet123" } }
};
// Later, remount with saved props
<ComponentFormContainer configuredProps={saved} />
// The "Drive" field is hidden even though it has a saved value
Root cause:
In form-context.tsx
line 167, enabledOptionalProps
resets to {}
when component.key
changes, but there's no logic to re-enable optional fields that have values in the configuredProps
.
Suggested fix:
Add a useEffect that scans configuredProps
on mount and automatically enables optional props with values:
useEffect(() => {
const propsToEnable: Record<string, boolean> = {};
for (const prop of configurableProps) {
if (prop.optional) {
const value = configuredProps[prop.name as keyof ConfiguredProps<T>];
if (value !== undefined) {
propsToEnable[prop.name] = true;
}
}
}
if (Object.keys(propsToEnable).length > 0) {
setEnabledOptionalProps(prev => ({
...prev,
...propsToEnable,
}));
}
}, [component.key, configurableProps, configuredProps]);
Issue 3: Optional prop values lost during sync 🟡
Impact: High - Silent data loss during dynamic props reload
What we observed:
When dynamic props reload (e.g., after selecting a worksheet that triggers reloadProps
), values from disabled optional props get lost.
Root cause:
The sync effect in form-context.tsx
around line 412-420 has a continue
statement for disabled optional props without preserving their existing values first.
Suggested fix:
if (prop.optional && !optionalPropIsEnabled(prop)) {
// Preserve the value even if the optional prop is disabled
const value = configuredProps[prop.name as keyof ConfiguredProps<T>];
if (value !== undefined) {
newConfiguredProps[prop.name as keyof ConfiguredProps<T>] = value;
}
continue;
}
Issue 4: Dropdown options accumulate instead of replacing 🟡
Impact: High - Wrong options shown, confusing UX
What we observed:
When you change a parent dropdown field (like changing "Channel Type" from "Channels" to "Direct Messages" in Slack), the child dropdown shows options from BOTH queries mixed together instead of replacing them.
How to reproduce:
- Select Channel Type = "Channels"
- Channel dropdown shows:
["#general", "#random", ...]
- Change Channel Type = "Direct Messages"
- Channel dropdown shows:
["#general", "#random", "@user1", "@user2", ...]
Expected: Should only show ["@user1", "@user2", ...]
Root cause:
In RemoteOptionsContainer.tsx
, the pageable.data
array always appends new options without detecting if this is a fresh query vs pagination.
Suggested fix:
Implement page-based logic - when page === 0
(fresh query), replace options; when page > 0
(pagination), append options.
Issue 5: Duplicate API calls when selecting options 🟡
Impact: Medium - Performance concern, potential stale data
What we observed:
Every time you select an option from a dropdown, two /configure
API calls fire:
- First call:
configured_props: {}
(empty) - Second call:
configured_props: {field: value}
(correct)
Root cause:
In form-context.tsx
around line 92-94, the setConfiguredProp
function calls updateConfiguredPropsQueryDisabledIdx
synchronously, which updates queryDisabledIdx
state immediately. But setConfiguredProps
schedules an async state update. This causes children to re-render twice with mismatched state.
Suggested fix:
Remove the synchronous call and move the queryDisabledIdx
update to a reactive useEffect that watches configuredProps
changes.
Issue 6: Integer dropdown values get deleted on dynamic props reload 🔴
Impact: Critical - Users cannot complete forms with integer remote options
What we observed:
With Google Sheets component:
- Select a spreadsheet → works
- Select a worksheet from dropdown → value appears
- See "Loading dynamic props..."
- Worksheet field clears back to empty
Root cause:
Remote options store integer values in label-value format: {__lv: {label: "Alpha - Dev", value: 1628247051}}
. But the sync effect in form-context.tsx
line 428 checks prop.type === "integer" && typeof value !== "number"
and deletes the value because it's an object, not recognizing this as the correct format for remote options.
Suggested fix:
if (prop.type === "integer" && typeof value !== "number") {
// Preserve label-value format from remote options dropdowns
if (!(value && typeof value === "object" && "__lv" in value)) {
delete newConfiguredProps[prop.name as keyof ConfiguredProps<T>];
} else {
newConfiguredProps[prop.name as keyof ConfiguredProps<T>] = value;
}
}
Testing & Solutions
I've tested all these scenarios extensively with:
- Google Sheets "Update Row" component
- Slack "Send Message" component
- Various combinations of pre-configured props
- Dynamic props reload scenarios
- Optional props enabled/disabled
I've implemented fixes for all these issues in a fork. I'll be raising a PR shortly with these changes if that would be helpful, or happy to discuss alternative approaches if there's a different design intention I'm missing.
Environment
@pipedream/connect-react
: 2.0.0- React: 18.3.1
- Next.js: 15
- Use case: Production app with persistent form state
Happy to provide more details or clarification on any of these issues. Thanks for the great library!