unadlib / mutative

Efficient immutable updates, 2-6x faster than naive handcrafted reducer, and more than 10x faster than Immer.
http://mutative.js.org/
MIT License
1.58k stars 18 forks source link

Modification inside create is lost and differs from immer #18

Closed Gongreg closed 10 months ago

Gongreg commented 11 months ago

Hello. I've noticed part of user written code that used to work with immer does not work with mutative. Here is code snippet:

import { create } from 'mutative';
import { produce } from 'immer';

const baseState = {
  array: [
    {
     one: {
       two: 3,
     },
    }
   ]
};

const created = create(baseState, (draft) => {
  draft.array[0].one.two = 2

  draft.array = [draft.array[0]]
});

created.array[0].one.two // 3

const produced = produce(baseState, (draft) => {
  draft.array[0].one.two = 2

  draft.array = [draft.array[0]]
});

produced.array[0].one.two // 2

Curious to hear is this expected?

unadlib commented 10 months ago

hi @Gongreg , it's an issue with the finalization draft process, and I am fixing it.

unadlib commented 10 months ago

hi @Gongreg , I've fixed the issue and I've released the latest version 0.7.0.

Immer has the following issue.

import { produce } from 'immer';
import { create } from 'mutative';

const baseState = {
  array: [
    {
      one: {
        two: {
          three: 3,
        },
      },
    },
  ],
};

const created = create(baseState, (draft) => {
  draft.array[0].one.two.three = 2;
  const two = draft.array[0].one.two;
  const one = new Set();
  draft.array = [{ one }];
  one.add(two);
  expect(Array.from(draft.array[0].one)[0].three).toBe(2);
});
expect(Array.from(created.array[0].one)[0].three).toBe(2); // it's ok

const produced = produce(baseState, (draft: any) => {
  draft.array[0].one.two.three = 2;
  const two = draft.array[0].one.two;
  const one = new Set();
  draft.array = [{ one }];
  one.add(two);
  expect(Array.from(draft.array[0].one)[0].three).toBe(2);
});

// throw error
expect(() => Array.from(produced.array[0].one)[0].three).toThrowError(
  `Cannot perform 'get' on a proxy that has been revoked`
);

Thank you so much for reporting this issue.

Gongreg commented 10 months ago

Thanks for fixing!