Memoized selector with computation in @ngrx/store





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







0















My normalized ngrx store looks like this:



export interface State {
carts: EntityState<Cart>;
items: EntityState<Item>;
}

export interface Cart {
id: number;
maxVolume: number;
}

export interface Item {
id: number;
cartId: number;
volume: number;
}


It's a pretty basic setup where a cart can contain several items.
My selector needs to return an array with all the carts with arrays containing their items, but also compute if items are in danger of dropping out of their respective cart:



export const select: MemoizedSelector<object, any> = createSelector(
selectAllCarts, selectAllItems,
(allCarts: Cart, allItems: Item) => {
return allCarts.map(c => {
const items = allItems.filter(i => i.cartId == i.id);
return {
id: c.id,
items: items.map(i => {
// computations, should not run if cart's items have not changed
// needs to be memoized
const computed = isCartOverfilled(i, c, items);
return {
id: i.id,
mightFallOut: computed//computed value needs to be output
}
})
}
});
});


Every time an item updates, isCartOverfilled will run for each item in the store. But, isCartOverfilled is potentially expensive and depends only on the items inside a cart. When an item updates, e.g. gets added to a cart, isCartOverfilled should execute ONLY for the items inside, i.e. memoized by cart id.



How do I achieve this?



I have tried selecting items from a single cart:



export const selectCart = (cartId: number) => createSelector(
selectItemsByCartId(cartId), selectCartById(cartId),
(items: Item, cart: Cart) => {
return {
id: cart.id,
items: items.map(i => {
const computed = isCartOverfilled(i, cart, items);
return {
id: i.id,
mightFallOut: computed
}
})
}
});


This selector would not excessively compute, but I need all the carts, and I'm not sure if it's doable with a selector.










share|improve this question































    0















    My normalized ngrx store looks like this:



    export interface State {
    carts: EntityState<Cart>;
    items: EntityState<Item>;
    }

    export interface Cart {
    id: number;
    maxVolume: number;
    }

    export interface Item {
    id: number;
    cartId: number;
    volume: number;
    }


    It's a pretty basic setup where a cart can contain several items.
    My selector needs to return an array with all the carts with arrays containing their items, but also compute if items are in danger of dropping out of their respective cart:



    export const select: MemoizedSelector<object, any> = createSelector(
    selectAllCarts, selectAllItems,
    (allCarts: Cart, allItems: Item) => {
    return allCarts.map(c => {
    const items = allItems.filter(i => i.cartId == i.id);
    return {
    id: c.id,
    items: items.map(i => {
    // computations, should not run if cart's items have not changed
    // needs to be memoized
    const computed = isCartOverfilled(i, c, items);
    return {
    id: i.id,
    mightFallOut: computed//computed value needs to be output
    }
    })
    }
    });
    });


    Every time an item updates, isCartOverfilled will run for each item in the store. But, isCartOverfilled is potentially expensive and depends only on the items inside a cart. When an item updates, e.g. gets added to a cart, isCartOverfilled should execute ONLY for the items inside, i.e. memoized by cart id.



    How do I achieve this?



    I have tried selecting items from a single cart:



    export const selectCart = (cartId: number) => createSelector(
    selectItemsByCartId(cartId), selectCartById(cartId),
    (items: Item, cart: Cart) => {
    return {
    id: cart.id,
    items: items.map(i => {
    const computed = isCartOverfilled(i, cart, items);
    return {
    id: i.id,
    mightFallOut: computed
    }
    })
    }
    });


    This selector would not excessively compute, but I need all the carts, and I'm not sure if it's doable with a selector.










    share|improve this question



























      0












      0








      0








      My normalized ngrx store looks like this:



      export interface State {
      carts: EntityState<Cart>;
      items: EntityState<Item>;
      }

      export interface Cart {
      id: number;
      maxVolume: number;
      }

      export interface Item {
      id: number;
      cartId: number;
      volume: number;
      }


      It's a pretty basic setup where a cart can contain several items.
      My selector needs to return an array with all the carts with arrays containing their items, but also compute if items are in danger of dropping out of their respective cart:



      export const select: MemoizedSelector<object, any> = createSelector(
      selectAllCarts, selectAllItems,
      (allCarts: Cart, allItems: Item) => {
      return allCarts.map(c => {
      const items = allItems.filter(i => i.cartId == i.id);
      return {
      id: c.id,
      items: items.map(i => {
      // computations, should not run if cart's items have not changed
      // needs to be memoized
      const computed = isCartOverfilled(i, c, items);
      return {
      id: i.id,
      mightFallOut: computed//computed value needs to be output
      }
      })
      }
      });
      });


      Every time an item updates, isCartOverfilled will run for each item in the store. But, isCartOverfilled is potentially expensive and depends only on the items inside a cart. When an item updates, e.g. gets added to a cart, isCartOverfilled should execute ONLY for the items inside, i.e. memoized by cart id.



      How do I achieve this?



      I have tried selecting items from a single cart:



      export const selectCart = (cartId: number) => createSelector(
      selectItemsByCartId(cartId), selectCartById(cartId),
      (items: Item, cart: Cart) => {
      return {
      id: cart.id,
      items: items.map(i => {
      const computed = isCartOverfilled(i, cart, items);
      return {
      id: i.id,
      mightFallOut: computed
      }
      })
      }
      });


      This selector would not excessively compute, but I need all the carts, and I'm not sure if it's doable with a selector.










      share|improve this question
















      My normalized ngrx store looks like this:



      export interface State {
      carts: EntityState<Cart>;
      items: EntityState<Item>;
      }

      export interface Cart {
      id: number;
      maxVolume: number;
      }

      export interface Item {
      id: number;
      cartId: number;
      volume: number;
      }


      It's a pretty basic setup where a cart can contain several items.
      My selector needs to return an array with all the carts with arrays containing their items, but also compute if items are in danger of dropping out of their respective cart:



      export const select: MemoizedSelector<object, any> = createSelector(
      selectAllCarts, selectAllItems,
      (allCarts: Cart, allItems: Item) => {
      return allCarts.map(c => {
      const items = allItems.filter(i => i.cartId == i.id);
      return {
      id: c.id,
      items: items.map(i => {
      // computations, should not run if cart's items have not changed
      // needs to be memoized
      const computed = isCartOverfilled(i, c, items);
      return {
      id: i.id,
      mightFallOut: computed//computed value needs to be output
      }
      })
      }
      });
      });


      Every time an item updates, isCartOverfilled will run for each item in the store. But, isCartOverfilled is potentially expensive and depends only on the items inside a cart. When an item updates, e.g. gets added to a cart, isCartOverfilled should execute ONLY for the items inside, i.e. memoized by cart id.



      How do I achieve this?



      I have tried selecting items from a single cart:



      export const selectCart = (cartId: number) => createSelector(
      selectItemsByCartId(cartId), selectCartById(cartId),
      (items: Item, cart: Cart) => {
      return {
      id: cart.id,
      items: items.map(i => {
      const computed = isCartOverfilled(i, cart, items);
      return {
      id: i.id,
      mightFallOut: computed
      }
      })
      }
      });


      This selector would not excessively compute, but I need all the carts, and I'm not sure if it's doable with a selector.







      typescript ngrx ngrx-store reselect ngrx-entity






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jan 3 at 16:53







      Ante Novokmet

















      asked Jan 3 at 14:16









      Ante NovokmetAnte Novokmet

      1436




      1436
























          1 Answer
          1






          active

          oldest

          votes


















          0














          As the state is already changed the selector will recalculate.



          But you can achieve using keeping another state for cart and when you dispatch addCart Item action you can update the cart with single item instead of using selector.



          export interface State {
          carts: EntityState<Cart>;
          cartOverFilled: SomeState or part of Cart State <---
          items: EntityState<Item>;
          }


          or



          export interface State {
          carts: EntityState<CartState>;
          items: EntityState<Item>;
          }

          export interface CartState {
          cart: Cart;
          overFilled: any
          }

          export interface Cart {
          id: number;
          maxVolume: number;
          }



          1. Add one more state with values to check overfilled;

          2. Create an effect for ofType 'Add to cart '

          3. Create another action to recalculate the with existing state of overfilled with incoming item.






          share|improve this answer


























          • I am aware of the first point. As for the second, are you suggesting I move computation to the reducer and actually store the computed state to store? Is there a way to create such a selector that when it recalculates, only recomputes items from a single cart?

            – Ante Novokmet
            Jan 3 at 16:43











          • Dispatch another action

            – rijin
            Jan 3 at 16:45












          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54024066%2fmemoized-selector-with-computation-in-ngrx-store%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          0














          As the state is already changed the selector will recalculate.



          But you can achieve using keeping another state for cart and when you dispatch addCart Item action you can update the cart with single item instead of using selector.



          export interface State {
          carts: EntityState<Cart>;
          cartOverFilled: SomeState or part of Cart State <---
          items: EntityState<Item>;
          }


          or



          export interface State {
          carts: EntityState<CartState>;
          items: EntityState<Item>;
          }

          export interface CartState {
          cart: Cart;
          overFilled: any
          }

          export interface Cart {
          id: number;
          maxVolume: number;
          }



          1. Add one more state with values to check overfilled;

          2. Create an effect for ofType 'Add to cart '

          3. Create another action to recalculate the with existing state of overfilled with incoming item.






          share|improve this answer


























          • I am aware of the first point. As for the second, are you suggesting I move computation to the reducer and actually store the computed state to store? Is there a way to create such a selector that when it recalculates, only recomputes items from a single cart?

            – Ante Novokmet
            Jan 3 at 16:43











          • Dispatch another action

            – rijin
            Jan 3 at 16:45
















          0














          As the state is already changed the selector will recalculate.



          But you can achieve using keeping another state for cart and when you dispatch addCart Item action you can update the cart with single item instead of using selector.



          export interface State {
          carts: EntityState<Cart>;
          cartOverFilled: SomeState or part of Cart State <---
          items: EntityState<Item>;
          }


          or



          export interface State {
          carts: EntityState<CartState>;
          items: EntityState<Item>;
          }

          export interface CartState {
          cart: Cart;
          overFilled: any
          }

          export interface Cart {
          id: number;
          maxVolume: number;
          }



          1. Add one more state with values to check overfilled;

          2. Create an effect for ofType 'Add to cart '

          3. Create another action to recalculate the with existing state of overfilled with incoming item.






          share|improve this answer


























          • I am aware of the first point. As for the second, are you suggesting I move computation to the reducer and actually store the computed state to store? Is there a way to create such a selector that when it recalculates, only recomputes items from a single cart?

            – Ante Novokmet
            Jan 3 at 16:43











          • Dispatch another action

            – rijin
            Jan 3 at 16:45














          0












          0








          0







          As the state is already changed the selector will recalculate.



          But you can achieve using keeping another state for cart and when you dispatch addCart Item action you can update the cart with single item instead of using selector.



          export interface State {
          carts: EntityState<Cart>;
          cartOverFilled: SomeState or part of Cart State <---
          items: EntityState<Item>;
          }


          or



          export interface State {
          carts: EntityState<CartState>;
          items: EntityState<Item>;
          }

          export interface CartState {
          cart: Cart;
          overFilled: any
          }

          export interface Cart {
          id: number;
          maxVolume: number;
          }



          1. Add one more state with values to check overfilled;

          2. Create an effect for ofType 'Add to cart '

          3. Create another action to recalculate the with existing state of overfilled with incoming item.






          share|improve this answer















          As the state is already changed the selector will recalculate.



          But you can achieve using keeping another state for cart and when you dispatch addCart Item action you can update the cart with single item instead of using selector.



          export interface State {
          carts: EntityState<Cart>;
          cartOverFilled: SomeState or part of Cart State <---
          items: EntityState<Item>;
          }


          or



          export interface State {
          carts: EntityState<CartState>;
          items: EntityState<Item>;
          }

          export interface CartState {
          cart: Cart;
          overFilled: any
          }

          export interface Cart {
          id: number;
          maxVolume: number;
          }



          1. Add one more state with values to check overfilled;

          2. Create an effect for ofType 'Add to cart '

          3. Create another action to recalculate the with existing state of overfilled with incoming item.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jan 4 at 15:00

























          answered Jan 3 at 14:52









          rijinrijin

          1,059515




          1,059515













          • I am aware of the first point. As for the second, are you suggesting I move computation to the reducer and actually store the computed state to store? Is there a way to create such a selector that when it recalculates, only recomputes items from a single cart?

            – Ante Novokmet
            Jan 3 at 16:43











          • Dispatch another action

            – rijin
            Jan 3 at 16:45



















          • I am aware of the first point. As for the second, are you suggesting I move computation to the reducer and actually store the computed state to store? Is there a way to create such a selector that when it recalculates, only recomputes items from a single cart?

            – Ante Novokmet
            Jan 3 at 16:43











          • Dispatch another action

            – rijin
            Jan 3 at 16:45

















          I am aware of the first point. As for the second, are you suggesting I move computation to the reducer and actually store the computed state to store? Is there a way to create such a selector that when it recalculates, only recomputes items from a single cart?

          – Ante Novokmet
          Jan 3 at 16:43





          I am aware of the first point. As for the second, are you suggesting I move computation to the reducer and actually store the computed state to store? Is there a way to create such a selector that when it recalculates, only recomputes items from a single cart?

          – Ante Novokmet
          Jan 3 at 16:43













          Dispatch another action

          – rijin
          Jan 3 at 16:45





          Dispatch another action

          – rijin
          Jan 3 at 16:45




















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54024066%2fmemoized-selector-with-computation-in-ngrx-store%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          MongoDB - Not Authorized To Execute Command

          in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith

          Npm cannot find a required file even through it is in the searched directory