Skip to content

Conversation

@DrEverr
Copy link
Member

@DrEverr DrEverr commented Dec 2, 2025

useRef(handleBytesToJson) captures the handleBytesToJson function at the time of the first render.
When kind or chainSpec state updates, the function stored in handleBytesToJsonRef.current still has the old values in its closure.
Addin handleBytesToJsonRef.current = handleBytesToJson; updates the ref to point to the current version of handleBytesToJson on every render, which has the current values of kind and chainSpec in its closure.

@netlify
Copy link

netlify bot commented Dec 2, 2025

Deploy Preview for fluffy-codec ready!

Name Link
🔨 Latest commit fb70104
🔍 Latest deploy log https://app.netlify.com/projects/fluffy-codec/deploys/692ecbbc9961c50008f1c9d4
😎 Deploy Preview https://deploy-preview-57--fluffy-codec.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 2, 2025

📝 Walkthrough

Walkthrough

A mutable ref is added to the handleBytesToJson function in Codec.tsx to maintain the latest function reference. After the function's creation, the ref is updated to ensure useEffect and other closures access the current version without requiring effect re-creation.

Changes

Cohort / File(s) Summary
Ref assignment for closure capture
src/pages/Codec.tsx
Added mutable ref assignment to maintain the latest handleBytesToJson function reference for use in useEffect and closures without triggering re-creation.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

  • Verify that the ref assignment correctly captures the latest function and that closures in useEffect properly reference it
  • Ensure no side effects or memory leaks result from maintaining this mutable ref
  • Confirm the change doesn't alter the function's behavior or public API

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning No pull request description was provided by the author, making it impossible to assess whether the description relates to the changeset. Add a pull request description explaining the purpose of the ref update, why it was necessary, and how it improves the component's behavior.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'setting current value, to correctly handle change' is vague and does not clearly convey the specific change being made (updating a mutable ref for handleBytesToJson to prevent stale closures). Consider revising the title to be more specific, such as 'Update handleBytesToJson ref to prevent stale closures in useEffect' or similar to better describe the actual technical change.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch maso-fix-codec-change

Comment @coderabbitai help to get the list of available commands and usage tips.

@DrEverr DrEverr requested a review from tomusdrw December 2, 2025 11:22
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/pages/Codec.tsx (2)

55-75: Consider decoding newInput instead of bytesInput to avoid stale state

Inside handleBytesToJson, you ignore the newInput argument when decoding and instead use the bytesInput state. Because state updates are async, this can leave the decode step one render behind (especially on onChange paths or URL-driven updates) and makes the logic more sensitive to closure timing than necessary.

You can make the function more direct and robust by decoding the value you were just given:

-      const decoded = codec.Decoder.decodeObject<unknown>(
-        kindDescriptor.clazz.Codec,
-        bytes.BytesBlob.parseBlob(bytesInput),
-        spec?.spec,
-      );
+      const decoded = codec.Decoder.decodeObject<unknown>(
+        kindDescriptor.clazz.Codec,
+        bytes.BytesBlob.parseBlob(newInput),
+        spec?.spec,
+      );

This aligns the decode with the source of truth for the current change and avoids relying on when setBytesInput has taken effect.


102-115: Ref update fixes stale callback, but effect can still see previous kind/chainSpec for URL-only changes

Updating handleBytesToJsonRef.current on every render is the right move to avoid the “ref holds the initial callback” problem; the effect will now always call the latest handleBytesToJson.

However, the useEffect below still does:

if (validSearchParams.kind !== undefined) {
  setKind(validSearchParams.kind.name);
}
if (validSearchParams.chainSpec !== undefined) {
  setChainSpec(validSearchParams.chainSpec.name);
}
if (validSearchParams.data !== null) {
  handleBytesToJsonRef.current(validSearchParams.data);
}

Because setKind / setChainSpec are async, the call to handleBytesToJsonRef.current(...) runs with whatever kind/chainSpec were in the render that scheduled this effect. If the URL query can change from outside this component (e.g., navigation that only updates kind/flavor), you can still end up decoding and even rewriting the URL using the previous kind/chainSpec instead of what’s in validSearchParams.

To make this more robust, consider one of these approaches:

  • Let handleBytesToJson accept optional overrides and use them in the effect:
// signature sketch
const handleBytesToJson = (
  newInput: string,
  opts?: { kindOverride?: string; chainSpecOverride?: string },
) => {
  const effectiveKind = opts?.kindOverride ?? kind;
  const effectiveChainSpec = opts?.chainSpecOverride ?? chainSpec;
  // use effectiveKind / effectiveChainSpec everywhere
};

// in the effect
if (validSearchParams.data !== null) {
  handleBytesToJsonRef.current(validSearchParams.data, {
    kindOverride: validSearchParams.kind?.name,
    chainSpecOverride: validSearchParams.chainSpec?.name,
  });
}
  • Or, move the decode logic used for URL-driven initialisation into the effect itself and base it purely on validSearchParams rather than the component state.

Also, minor/optional: if you’d like to avoid mutating the ref during render, you can instead update it in a small useEffect that depends on handleBytesToJson; the current approach is common and works, but an effect keeps all writes out of render if you prefer that style.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ff943ce and fb70104.

📒 Files selected for processing (1)
  • src/pages/Codec.tsx (1 hunks)

@tomusdrw tomusdrw merged commit 2af2ca0 into main Dec 2, 2025
6 checks passed
@tomusdrw tomusdrw deleted the maso-fix-codec-change branch December 2, 2025 12:52
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.

3 participants