Skip to content

Conversation

vict0rcarvalh0
Copy link
Contributor

@vict0rcarvalh0 vict0rcarvalh0 commented Sep 1, 2025

Fix: React hooks should respect enabled field (Issue #224)

Problem

All React hooks in the @gillsdk/react package were hardcoding the enabled field in their useQuery calls, which completely overrode any user-provided enabled option. This meant that users couldn't control when hooks should run, even when they explicitly set enabled: false in their options.

Example of the problem:

// User's intention: disable the query
const { account } = useAccount({
  address: "SomeAddress",
  options: {
    enabled: false, // This was being ignored
  }
});
// The query would still run because enabled was hardcoded to !!address

Root Cause

The hooks were using this pattern:

const { data, ...rest } = useQuery({
  ...options,           // User's options spread first
  queryKey: [...],
  queryFn: async () => { ... },
  enabled: !!address,   // This overwrote options.enabled!
});

Since enabled: !!address came after ...options, it would override any enabled value the user provided.

Solution

Changed all affected hooks to properly combine the user's enabled value with the hook's internal validation logic:

const { data, ...rest } = useQuery({
  ...options,
  queryKey: [...],
  queryFn: async () => { ... },
  enabled: (options?.enabled ?? true) && !!address, // Now respects user's enabled field
});

How the fix works:

  • options?.enabled ?? true - Uses the user's enabled value, defaults to true if not provided
  • && !!address - Combines with the hook's internal validation logic using logical AND
  • If user sets enabled: false, the query won't run regardless of other conditions
  • If user doesn't provide enabled (or sets it to true), it behaves exactly as before

Hooks Already Working Correctly

These hooks already respected the user's enabled field since they don't override it:

  • useSlot
  • useLatestBlockhash
  • useRecentPrioritizationFees

Testing

The fix has been verified with a comprehensive test that covers all scenarios:

Test File: test_enabled_logic.js

Note

Test file deleted after the expected results.

// Simple test to verify the enabled field logic
const testEnabledLogic = () => {
  // Test cases for our enabled field fix
  const testCases = [
    {
      name: "User enabled: true, address exists",
      userEnabled: true,
      address: "SomeAddress",
      expected: true
    },
    {
      name: "User enabled: false, address exists", 
      userEnabled: false,
      address: "SomeAddress",
      expected: false
    },
    {
      name: "User enabled: undefined (default true), address exists",
      userEnabled: undefined,
      address: "SomeAddress", 
      expected: true
    },
    {
      name: "User enabled: true, address empty",
      userEnabled: true,
      address: "",
      expected: false
    },
    {
      name: "User enabled: false, address empty",
      userEnabled: false,
      address: "",
      expected: false
    },
    {
      name: "User enabled: undefined (default true), address empty",
      userEnabled: undefined,
      address: "",
      expected: false
    }
  ];

  console.log("Testing enabled field logic: (options?.enabled ?? true) && !!address");
  
  testCases.forEach(test => {
    const options = test.userEnabled !== undefined ? { enabled: test.userEnabled } : {};
    const address = test.address;
    
    // This is the logic we implemented
    const result = (options?.enabled ?? true) && !!address;
    
    const status = result === test.expected ? "PASS" : "FAIL";
    console.log(`${status} ${test.name}: ${result} (expected: ${test.expected})`);
  });
};

testEnabledLogic();

Test Results:

Testing enabled field logic: (options?.enabled ?? true) && !!address
PASS User enabled: true, address exists: true (expected: true)
PASS User enabled: false, address exists: false (expected: false)
PASS User enabled: undefined (default true), address exists: true (expected: true)
PASS User enabled: true, address empty: false (expected: false)
PASS User enabled: false, address empty: false (expected: false)
PASS User enabled: undefined (default true), address empty: false (expected: false)

All test cases pass, confirming that the logic correctly:

  • Respects user's enabled: false setting
  • Defaults to true when enabled is not provided
  • Still validates required parameters (like address existence)
  • Combines both conditions properly with logical AND

Usage Examples

Before Fix (user's enabled was ignored)

const { account } = useAccount({
  address: "SomeAddress",
  options: {
    enabled: false, // This was ignored
  }
});
// The query would still run because enabled was hardcoded to !!address

After Fix (user's enabled is respected)

const { account } = useAccount({
  address: "SomeAddress", 
  options: {
    enabled: false, // This is now respected
  }
});
// The query will NOT run because user set enabled: false

Conditional queries now work properly

const [shouldFetch, setShouldFetch] = useState(false);

const { account } = useAccount({
  address: "SomeAddress",
  options: {
    enabled: shouldFetch, // Now works as expected
  }
});

Backwards Compatibility

Fully backwards compatible - existing code continues to work exactly as before since:

  • Default behavior when enabled is not provided remains the same (true)
  • All existing validation logic is preserved
  • No breaking changes to the API

All React hooks were hardcoding the enabled field, overriding any
user-provided enabled option. This change ensures that hooks properly
combine the user's enabled value with their internal validation logic.

Closes issue: hooks should respect enabled field
Copy link

changeset-bot bot commented Sep 1, 2025

🦋 Changeset detected

Latest commit: 45b12b0

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 5 packages
Name Type
@gillsdk/react Patch
@gillsdk/examples-basics Patch
@gillsdk/examples-tokens Patch
@gillsdk/tests-e2e Patch
@gillsdk/solana-pay Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link

bundlemon bot commented Oct 2, 2025

BundleMon

Files updated (3)
Status Path Size Limits
react/dist/index.browser.mjs
2.12KB (+14B +0.65%) -
react/dist/index.native.mjs
2.12KB (+14B +0.65%) -
react/dist/index.node.mjs
2.12KB (+14B +0.65%) -
Unchanged files (13)
Status Path Size Limits
gill/dist/programs/index.node.mjs
9.84KB -
gill/dist/index.browser.mjs
5.53KB -
gill/dist/index.native.mjs
5.53KB -
gill/dist/programs/token/index.node.mjs
4.11KB -
solana-pay/dist/index.browser.mjs
1.72KB -
solana-pay/dist/index.native.mjs
1.72KB -
solana-pay/dist/index.node.mjs
1.72KB -
gill/dist/node/index.node.mjs
948B -
gill/dist/index.node.mjs
519B -
svelte/dist/index.browser.mjs
265B -
vue/dist/index.browser.mjs
265B -
svelte/dist/index.node.mjs
262B -
vue/dist/index.node.mjs
262B -

Total files change +42B +0.11%

Final result: ✅

View report in BundleMon website ➡️


Current branch size history | Target branch size history

Copy link
Collaborator

@nickfrosty nickfrosty left a comment

Choose a reason for hiding this comment

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

Thanks for fixing this @vict0rcarvalh0!
I just manually resolved all the merge conflicts (since I merged a bunch of other PRs just before this) and added your same fix to the other hooks that were just merged

@nickfrosty nickfrosty merged commit 0474578 into gillsdk:master Oct 2, 2025
6 checks passed
@github-actions github-actions bot mentioned this pull request Oct 2, 2025
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.

2 participants