Repository: pmndrs/valtio (ts)

Issue:
Bug with history (again?)
Hello again, I think I found something.

[sandbox link](https://codesandbox.io/s/react-typescript-forked-6leim?file=/src/App.tsx)

I'm trying to implement transition (jump) between different states in my project and found one issue.

If I try to undo or redo a state in a loop it doesn't work as expected.

PS: Loop is just an example for this issue, I know I can get the value directly from the snapshots array.

Expected:
Case 1:
initial value 0
UpdateValue (x3) -> undo by step (x3) -> redo by step (x3) -> 3

Case 2:
initial value 0
UpdateValue (x3) -> undo all -> redo all -> 3

-----------------------------------------------------------------------------

Actual:
Case 1:
initial value 0
UpdateValue (x3) -> undo by step (x3) -> redo by step (x3) -> 3        <- fine

Case 2:
initial value 0
UpdateValue (x3) -> undo all -> redo all -> 0                                          <- bad

Pull request description:
fix(utils): multiple redos at once with proxyWithHistory
close #323

Patch:
diff --git a/src/utils/proxyWithHistory.ts b/src/utils/proxyWithHistory.ts
index 93f7872..a49acf7 100644
--- a/src/utils/proxyWithHistory.ts
+++ b/src/utils/proxyWithHistory.ts
@@ -62,7 +62,7 @@ export const proxyWithHistory = <V>(initialValue: V, skipSubscribe = false) => {
     subscribe: () =>
       subscribe(proxyObject, (ops) => {
         if (
-          ops.some(
+          ops.every(
             (op) =>
               op[1][0] === 'value' &&
               (op[0] !== 'set' || op[2] !== proxyObject.history.wip)


Test patch:
diff --git a/tests/history.test.tsx b/tests/history.test.tsx
index 23f7dda..1f86cb8 100644
--- a/tests/history.test.tsx
+++ b/tests/history.test.tsx
@@ -180,3 +180,50 @@ it('count in nested object', async () => {
   fireEvent.click(getByText('undo'))
   await findByText('count: 0')
 })
+
+it('multiple redos at once (#323)', async () => {
+  const state = proxyWithHistory({ nested: { count: 0 } })
+
+  const Counter = () => {
+    const snap = useSnapshot(state)
+    return (
+      <>
+        <div>count: {snap.value.nested.count}</div>
+        <button onClick={() => ++state.value.nested.count}>inc</button>
+        <button
+          onClick={() => {
+            state.undo()
+            state.undo()
+          }}>
+          undo twice
+        </button>
+        <button
+          onClick={() => {
+            state.redo()
+            state.redo()
+          }}>
+          redo twice
+        </button>
+      </>
+    )
+  }
+
+  const { getByText, findByText } = render(
+    <StrictMode>
+      <Counter />
+    </StrictMode>
+  )
+
+  await findByText('count: 0')
+
+  fireEvent.click(getByText('inc'))
+  await findByText('count: 1')
+  fireEvent.click(getByText('inc'))
+  await findByText('count: 2')
+
+  fireEvent.click(getByText('undo twice'))
+  await findByText('count: 0')
+
+  fireEvent.click(getByText('redo twice'))
+  await findByText('count: 2')
+})