Skip to content

Fix undo/redo bug #186

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

ecfairle
Copy link

@ecfairle ecfairle commented Apr 6, 2025

Close #170. Forked from #174

@ecfairle
Copy link
Author

ecfairle commented Apr 7, 2025

I added onto @heruiwoniou 's PR since I have been using his branch for a while now in a project. There is a minor bug in his PR, that i believe has to do with the extra strokes being recorded on the canvas while the history is being updated. Which would explain why the undo/redo tests were failing.

I moved the history updating logic into the mouse-down / redo / undo / clear functions so there's no timing issues (basically record history on the "next" action instead of the "current" action).

Thanks for making this utility! Let me know if you have any questions or want me to make any changes.

@vinothpandian vinothpandian requested a review from Copilot April 14, 2025 16:26
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (2)

packages/react-sketch-canvas/src/ReactSketchCanvas/index.tsx:174

  • Resetting history to an empty array and setting historyPos to -1 may break subsequent undo/redo operations. Consider resetting to the initial state (e.g., history as [[]] and historyPos as 0) to maintain consistency.
setHistory([]);

packages/react-sketch-canvas/src/ReactSketchCanvas/index.tsx:199

  • [nitpick] Incrementing historyPos before adding the current stroke state via addLastStroke might capture a stale currentPaths state. Reviewing the order of operations to ensure accurate history capture is recommended.
setHistoryPos(pos => pos + 1);

@vinothpandian
Copy link
Owner

vinothpandian commented Apr 17, 2025

@ecfairle Thank you for the PR. I swear I’m going to take this weekend to merge these PRs and release the new version!

Can you please look at the review comments from Copilot if you have time?

@vinothpandian
Copy link
Owner

This implementation is creating a race condition when undo or redo buttons are pressed quickly, especially on large codebases. I'm trying to fix this

@ecfairle
Copy link
Author

Ah, right. It seems like the correct solution here is to refactor the logic for history-altering events as an event queue. I think that's closer to the underlying mental model for how a canvas should work. Anything else would be kind of hack imo. What do you think about doing that?

@vinothpandian
Copy link
Owner

Yes @ecfairle. That makes sense.

@ecfairle
Copy link
Author

How does this look?

@vinothpandian vinothpandian requested a review from Copilot May 13, 2025 13:57
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR fixes the undo/redo bug by adding support for loading canvas paths and refactoring the internal history management. Key changes include:

  • Adding new props and UI for loading paths via a "Load Paths" button.
  • Updating tests to cover undo/redo functionality with loaded paths and additional drawing scenarios.
  • Refactoring ReactSketchCanvas to replace separate stacks with a unified history and an operation queue for canvas operations.

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
packages/tests/src/stories/WithUndoRedoButtons.tsx Adds new loadPaths props, handler, and button for loading paths.
packages/tests/src/actions/undoRedo.spec.tsx Updates tests to pass the new paths prop and adds tests for loadPaths, undo after clear, and combined draw-load actions.
packages/react-sketch-canvas/src/ReactSketchCanvas/index.tsx Refactors canvas state management to use a unified history and operation queue for undo, redo, clear, and loadPaths operations.

addLastStroke();
setCurrentPaths((path) => [...path, ...operation.payload!]);
setHistoryPos(pos => pos + 1);
setHistory(his => [...his.slice(0, historyPos+1), [...currentPaths, ...operation.payload!]]);
Copy link
Preview

Copilot AI May 13, 2025

Choose a reason for hiding this comment

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

Referencing currentPaths directly here may risk using a stale state. Consider using a functional update or ensuring the latest state is accessed to avoid potential race conditions.

Suggested change
setHistory(his => [...his.slice(0, historyPos+1), [...currentPaths, ...operation.payload!]]);
setHistory(his => [...his.slice(0, historyPos+1), [...his[historyPos] || [], ...operation.payload!]]);

Copilot uses AI. Check for mistakes.

Comment on lines 246 to 247
setHistoryPos(pos => pos + 1);
addLastStroke();
Copy link
Preview

Copilot AI May 13, 2025

Choose a reason for hiding this comment

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

[nitpick] Consider calling addLastStroke() before incrementing historyPos to ensure that the current canvas state is recorded accurately prior to state changes.

Suggested change
setHistoryPos(pos => pos + 1);
addLastStroke();
addLastStroke();
setHistoryPos(pos => pos + 1);

Copilot uses AI. Check for mistakes.

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.

The clear operation is not included in the history stack
3 participants