Code Monkey home page Code Monkey logo

immer-adapter's People

Contributors

arturovt avatar dependabot[bot] avatar dmorosinotto avatar eranshmil avatar greenkeeper[bot] avatar renovate-bot avatar renovate[bot] avatar splincode avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

immer-adapter's Issues

Angular 12

Could someone release a new version with the updated dependencies for Angular 12?

getState within @ImmutableContext() returns a draft

So in our application we use this immer-adapter to help make our state immutable.
However, we recently ran into an issue where our production build breaks our apps.
It seems that everything is a lot stricter in production builds than in development build, which pointed us to a bunch of errors when using the getState method.

The getState method returns an immer draft, instead of, what we expected, a frozen instance of our state.
As you can see at this line:
https://github.com/ngxs-labs/immer-adapter/blob/master/src/lib/core/immer-adapter/common/immutable-state-context.ts#L23
It just creates a draft, casts it to the provided interface, calls it frozen and then returns it.

We tried to recreate this issue in an isolated project, and the results were the same.

So given an action like this, that finds an object (Dossier) in an array (dossiers) from the state, based on the dossierNumber:

@Action(DossiersActions.DeleteDossierByNumber)
@ImmutableContext()
public deleteDossierByNummer({ getState, setState }: StateContext<DossiersStateModel>, { dossierNumber }: DossiersActions.DeleteDossierByNumber): void {
  const found = getState().dossiers.find(d => d.dossierNumber === dossierNumber);
  console.log('found', found);
  if (!found) {
    throw new Error(`Could not find existing dossier to delete, for nummer ${dossierNumber}`);
  }
  setState((draft: DossiersStateModel) => {
    console.log('draft', draft)
    delete draft.dossiers[draft.dossiers.indexOf(found)];
    draft.dossiers = draft.dossiers.filter(dossier => !!dossier);
    return draft;
  });
}

We will receive an output like this, and the state would not have been modified (as the found object is nog present in the dossiers list):

found Proxy { ... }
draft Proxy { ... }

However, we would expect something like this (along with the found object to be removed from the dossiers list):

found Dossier { ... }
draft Proxy { ... }

If a working example is required, please do tell and I will try to provide a stack blitz as soon as possible.

Peer Dependency Support for angular v9 & v10

The peer dependencies for "@ngxs-labs/immer-adapter": "^3.0.5" from npm, seems to be having a different peer dependency, than what's in master.

"peerDependencies": {
    "@angular/core": "^8.0.2",
    "@ngxs/store": "^3.4.0",
    "immer": "^3.1.2"
  }

What would be required to publish a newer version of this library?

  • is it something like a manual PR that could be created & submitted? (what would be needed to do?)
  • or is it something like an automated process & which is broken, because of which its not getting published to npm?

Or, Should we not use this library at all and just use the immer library directly as stated here

When state is null/undefined ImmutableSelector/ImmutableContext stops working.

When the immer-adapter was using 'produce' as the mutate operator, in some cases the draft was undefined, and I could hadle it with an if. But now it just gives errors, even on Selectors, that I didn't had to handle before.

First I don't know if I should report separately but, when resetting the state using defaults or an object with the type of the State, the state's children are deleted, this is the most common cause of the undefined state. (Sometimes isn't needed to be a children of a reseted state to the state become undefined, but I couldn't reproduce what happens in my application)

The worst for me is the impossibility to handle this when I use immer-adapter.

Here is the stackblitz exemple: https://stackblitz.com/edit/angular-6gaame

Testing this repository I found a new error too, when using a ImmutableContext on a Receiver, other receivers on that state can't mutate the state without ImmutableContext.

Project won't update on npm?

The following alerts are being generated in my project:

warning " > @ngxs-labs/[email protected]" has incorrect peer dependency "@angular/core@^8.0.2".
warning " > @ngxs-labs/[email protected]" has incorrect peer dependency "immer@^3.1.2"

I noticed that in the project here on github these peer dependencies are updated, but in NPM it is not being updated.

Could you perform this update in NPM please?

Can't reset state returning 'defaults' or an object with the type of the state

I'm trying to reset my state, but I can't. I could use 'this.store.reset(State)', but sometimes I want to wait in somewhere by the action dispatched. And sometimes I want to reset everything except by one attribute. If the state has too many attributes it's easier create a function to assign each attribute to its default.

But the easiest would be just "return defaults", or "return { ...defaults, attribute: draft.attribute } as StateModel"

Here is the stackblitz exemple: https://stackblitz.com/edit/angular-c2nszw

Documentation typo?

I'm not really sure but as for declaration:

export class FeedZebra {
  public static readonly type = '[Animals] Feed zebra';
  constructor(public payload: string) {}
}

can it be used as:

@Action(Add)
public add({ getState, setState }: StateContext<AnimalsStateModel>, (...)

?

or should it be:

@Action(FeedZebra)
public add({ getState, setState }: StateContext<AnimalsStateModel>, (...)

?

or even:

@Action(FeedZebra)
 public feedZebra({ getState, setState }: StateContext<AnimalsStateModel>, (...)

?

Calling isDevMode() breaks production builds

Apparently the use of isDevMode() in src/lib/core/immer-adapter/decorators/immutable-context.decorator.ts added in PR #232 breaks production builds, because that function marks the app as initialized, and when enableProdMode() is executed we get the following error message: Cannot enable prod mode after platform setup.

This test case (which is a variant of a current test) simulates the error:

import { Component, enableProdMode } from '@angular/core';

(...)

describe('Pizzas state (productionMode = true)', () => {
    beforeEach(() => {
      enableProdMode();

      TestBed.configureTestingModule({
        imports: [NgxsModule.forRoot([PizzaState], { developmentMode: false })]
      });

      store = TestBed.get<Store>(Store);
      store.reset({ pizzas: JSON.parse(JSON.stringify(pizzasInitialState)) });
    });

    it('should add pizza toppings with using immutable mutation', () => {
      const previous = store.selectSnapshot(PizzaState);
      expect(previous).toEqual(pizzasInitialState);

      store.dispatch(new PizzasImmutableAction('tomato ham'));
      const newState = store.selectSnapshot(PizzaState);

      expect(previous).toEqual(pizzasInitialState);
      expect(newState).toEqual({
        margherita: {
          toppings: ['tomato sauce', 'mozzarella cheese', 'tomato ham'],
          prices: { small: '5.00', medium: '6.00', large: '7.00' }
        },
        prosciutto: {
          toppings: ['tomato ham', 'tomato sauce', 'mozzarella cheese', 'ham'],
          prices: { small: '6.50', medium: '7.50', large: '8.50' }
        }
      });

      const toppings = store.selectSnapshot(PizzaState.margheritaToppings);
      expect(previous).toEqual(pizzasInitialState);
      expect(toppings).toEqual(['tomato ham', 'mozzarella cheese', 'tomato sauce']);
    });

    it('should be correct autobind state context', () => {
      const previous = store.selectSnapshot(PizzaState);
      expect(previous).toEqual(pizzasInitialState);

      store.dispatch(new RemovePriceImmutableAction());
      const newState = store.selectSnapshot(PizzaState);
      expect(previous).toEqual(pizzasInitialState);

      expect(newState).toEqual({
        margherita: { toppings: ['tomato sauce', 'mozzarella cheese'], prices: null },
        prosciutto: { toppings: ['tomato sauce', 'mozzarella cheese', 'ham'], prices: null }
      });
    });
  });

Here you have an stackblitz example enabling prodMode: https://stackblitz.com/edit/angular-b7niec

dispatch in state

For the @ImmutableContext() you can use setState, but if you want to use dispatch as well... how do you combine this?

  @Action(SetAutocompleteRequest, { cancelUncompleted: true })
  @ImmutableContext()
  setAutocompleteRequest({setState, dispatch}: StateContext<ITrialState>, {payload}: SetAutocompleteRequest) {
    return this.autocompleteService.postAutocomplete(payload, 5).pipe(
      tap(response => {
        setState((state: ITrialState) => {
          state.autocompleteRequest = {...payload};
          return state;
        });
        // dispatch(
        //   new SetAutocompleteResponse(response)
        // );
      })
    )
  }

Error: TypeError: 'ownKeys' on proxy: trap result did not include 'scope'

after switching to @ngxs-labs/immer-adapter": "^2.0.1", i am getting following error

  @Mutation()
  @Action(CreateNewConversation)
  createConversation(ctx: StateContext<ChatBoxStateModel>) {
    const newConversation = new Conversation('payload.conversationId'); 
    ctx.setState((state: ChatBoxStateModel) => {
      state.conversations.push(newConversation);
      state.activeConversationId = newConversation.id;
      return state;
    });
  }
core.js:5567 ERROR TypeError: 'ownKeys' on proxy: trap result did not include 'scope'
    at Function.freeze (<anonymous>)
    at deepFreeze (ngxs-store.js:1514)
    at ngxs-store.js:1529
    at Array.forEach (<anonymous>)
    at deepFreeze (ngxs-store.js:1519)
    at Object.setState (ngxs-store.js:1607)
    at setStateValue (ngxs-store.js:1728)
    at Object.setState (ngxs-store.js:1785)
    at Object.setState (ngxs-labs-immer-adapter.js:82)
    at ChatBoxState.push.../../libs/chat-box/src/lib/state/chat-box.store.ts.ChatBoxState.createConversation (chat-box.store.ts:192)

Is the documentation example incorrect?

Hi everybody, i have a doubt. I've been testing the Immer adapter, but the example of the documentation I think is wrong because it gives me typing problems:

problem

so that this error did not give me, I had to return draft, but this does not say it in the documentation, in the documentation this is in the way that gives me error:

solution

So I do not know if I'm the one with the problem

Updating Reactive Form in State

I am having an issue using immer on a Reactive Form in my state. Here is an example of what I am doing.

import { State, Action, StateContext } from '@ngxs/store';
import { ImmutableContext } from '@ngxs-labs/immer-adapter';
export class UpdateName {
  public static readonly type = '[Animals] Update Name';
  constructor(public name: string) {}
}

@State<AnimalsStateModel>({
  name: 'animals',
  defaults: {
    zebra:  new FormGroup({
      name: new FormControl('zebra')
    }),
  }
})
export class AnimalState {

  @Action(UpdateName)
  @ImmutableContext()
  public updateName({ getState, setState }: StateContext<AnimalsStateModel>, payload: UpdateName): void {
    setState((state: AnimalsStateModel) => ({
       state.zebra.reset(payload);
       return state;
    }));
  }
}

This results in the following error...
Cannot assign to read only property '_pendingValue' of object '[object Object]'

Is there something I am doing wrong?

Versions
@angular/* : "^8.0.0"
@ngxs/store: "^3.6.0"
@ngxs-labs/immer-adapter: "^3.0.5"

Feature: Add simplify decorator `@Mutation`

Before

@State<AnimalsStateModel>({
    name: 'animals',
    defaults: {
        zebra: {
            food: [],
            name: 'zebra'
        },
        panda: {
            food: [],
            name: 'panda'
        }
    }
})
export class AnimalState {
    @Action(FeedZebra)
    public feedZebra(ctx: StateContext<AnimalsStateModel>, { payload }: FeedZebra) {
        produce(ctx, (draft: AnimalsStateModel) => draft.zebra.food.push(payload));
    }

    // OR if you are using ER approach

    @Receiver()
    public static feedZebra(ctx: StateContext<AnimalsStateModel>, { payload }: EmitterAction<string>) {
        produce(ctx, (draft: AnimalsStateModel) => draft.zebra.food.push(payload));
    }
}

After

@State<AnimalsStateModel>({
    name: 'animals',
    defaults: {
        zebra: {
            food: [],
            name: 'zebra'
        },
        panda: {
            food: [],
            name: 'panda'
        }
    }
})
export class AnimalState {
    
    @Mutation()
    public static feedZebra(draft, payload: string): AnimalsStateModel {
        draft.zebra.food.push(payload);
    }
}

peer dependency on @ngxs-labs/emitter ?

when I install @ngxs-labs/immer-adapter it says it depends on @ngxs-labs/emitter

is it really needed ? I don't see need for @ngxs-labs/emitter!

npm WARN @ngxs-labs/[email protected] requires a peer of @ngxs-labs/emitter@^1.6.0 but none is installed. You must install peer dependencies yourself.

@ImmutableContext() doesn't work with Receiver() properly

Before the change from produce operator to ImmutableContext decorator, the Receiver decorator from Emitter plugin had the implementation with immer-adapter documented here, now it doesn't.

It works with the new decorator, but it gives this error, preventing from compiling in aot:
erro-immer-emmiter

The immer-adapter won't give support anymore to Emmiter plugin?

Error: Cannot read property 'ctx' of undefined

If you use the ImmutableContext decorator together with an Action decorator that is subscribing to an Action that is also subscribed to from another State you get the following error:

ERROR TypeError: Cannot read property 'ctx' of undefined
 at push.../../node_modules/@ngxs-labs/immer-adapter/fesm5/ngxs-labs-immer-adapter.js.ImmutableStateContext.getState
// ...

An example to reproduce this:

@State<{}>({
  name: 'state1',
  defaults: {}
})
export class State1
{
  @Action(Action1)
  @ImmutableContext()
  public onMyAction1({ getState }: StateContext<{}>)
  {
    getState();
  }
}

@State<{}>({
  name: 'state2',
  defaults: {}
})
export class State2
{
  @Action(Action1)
  @ImmutableContext()
  public onMyAction1({ getState }: StateContext<{}>)
  {
    getState();
  }
}

STACKBLITZ

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.