Gathering detailed insights and metrics for mst-reference-pool
Gathering detailed insights and metrics for mst-reference-pool
Gathering detailed insights and metrics for mst-reference-pool
Gathering detailed insights and metrics for mst-reference-pool
MST Reference Pool is a MobX-State-Tree extension that allows you to use references to a pool of model instances in any store.
npm install mst-reference-pool
Typescript
Module System
Node Version
NPM Version
63.8
Supply Chain
97.1
Quality
77.9
Maintenance
100
Vulnerability
100
License
TypeScript (97.33%)
JavaScript (2.67%)
Total Downloads
18,697
Last Day
5
Last Week
48
Last Month
237
Last Year
5,665
23 Stars
36 Commits
10 Watching
2 Branches
30 Contributors
Latest Version
0.2.2
Package Id
mst-reference-pool@0.2.2
Unpacked Size
16.34 kB
Size
4.60 kB
File Count
8
NPM Version
7.24.2
Node Version
14.17.6
Cumulative downloads
Total Downloads
Last day
-28.6%
5
Compared to previous day
Last week
-9.4%
48
Compared to previous week
Last month
-18.6%
237
Compared to previous month
Last year
5.2%
5,665
Compared to previous year
2
mst-reference-pool
is a MobX-State-Tree extension that allows you to use references to a pool of model instances in any store.
Think of it like a hidden types.array
that you can point references to, plus a garbage collector to get rid of any instances that nothing is referencing anymore.
Whenever you have a frequently-changing array of instances and also have other references to those instances, mst-reference-pool
becomes a good option.
Let's look at an example ... say, an Instagram-like app. There's a feed of posts and also an optional currentPost
.
1import { types } from "mobx-state-tree" 2import { PostModel } from "./post" 3 4const RootStore = types 5 .model("RootStore", { 6 feed: types.array(PostModel), 7 currentPost: types.maybe(types.reference(PostModel)), 8 }) 9 .actions((store) => ({ 10 setFeed(newPosts) { 11 store.feed.replace(newPosts) 12 }, 13 setCurrentPost(newPost) { 14 store.currentPost = newPost 15 }, 16 }))
The thing with the feed is that you could scroll or refresh, and then the currentPost
would refer to a post that is no longer in the feed. This causes a reference error.
You might think you could make the currentPost
into its own types.maybe(PostModel)
, but when that post is in view for both the feed
and the currentPost
, now you have duplicate data (and identifiers).
This is where mst-reference-pool
shines!
Taking our Instagram-like app above, let's convert it to use a reference pool.
1import { types } from "mobx-state-tree" 2+import { withReferencePool } from "mst-reference-pool" 3import { PostModel } from "./post" 4 5const RootStore = types 6 .model("RootStore", { 7+ pool: types.array(PostModel), 8 feed: types.array(types.reference(PostModel)), 9 currentPost: types.maybe(types.reference(PostModel)), 10 }) 11+ .extend(withReferencePool(PostModel)) 12 .actions((store) => ({ 13 setFeed(newPosts) { 14+ const posts = store.addAllToPool(newPosts) 15 store.feed.replace(posts) 16 }, 17 setCurrentPost(newPost) { 18+ const post = store.addToPool(newPost) 19 store.currentPost = post 20 }, 21 }))
As you can see here, the primary difference is that we now have a pool
prop that contains the posts, and everything else is just a reference to those posts.
Before we set the feed
, we add the new posts to the pool with store.addAllToPool
, and then use those to establish the references.
We can do the same for a single reference. We just do store.addToPool
and then set the reference.
These references will always point to one instance in the pool. If addToPool
or addAllToPool
find an existing instance with the same identifier, they'll run applySnapshot
on that instance instead. This prevents duplicate items in your pool.
This is great, but without garbage collection, the pool will grow unbounded as the user scrolls through their feed. This is where the pool GC (garbage collector) comes in.
Add this action to your model, and pass into poolGC
any property where these posts might have a reference.
1.actions((store) => ({
2 gc() {
3 store.poolGC([
4 store.feed,
5 store.currentPost,
6 // perhaps some other store as well?
7 // search results is a common one
8 store.searchStore.filteredPosts,
9 // for nested references, you can spread a map, like so:
10 ...store.categories.map(cat => cat.posts)
11 ])
12 }
13}))
The GC is pretty fast, but you might not need to run it after every action. Generally, you'll run the GC anytime you do a larger refresh of your data. You can also run it anytime you remove or replace items from a list or property. Or, if you want, you could just run it every so often on a timer. It's up to you and what your project needs.
I recommend mainly doing it after a refresh.
1.actions((store) => ({ 2 setFeed(newPosts) { 3 const posts = store.addAllToPool(newPosts) 4 store.feed.replace(posts) 5 store.gc() 6 }, 7}))
Currently, you can only have one reference pool per store. So, if you want more than one reference pool, just make additional stores per model type.
Example:
1const FeedStore = types 2 .model("FeedStore", { 3 pool: types.array(PostModel), 4 feed: types.array(types.reference(PostModel)), 5 }) 6 .extend(withReferencePool(PostModel)) 7 8const UserStore = types 9 .model("UserStore", { 10 pool: types.array(UserModel), 11 users: types.array(types.reference(UserModel)), 12 }) 13 .extend(withReferencePool(UserModel)) 14 15const RootStore = types.model("RootStore", { 16 feedStore: FeedStore, 17 userStore: UserStore, 18})
You can use a pool across multiple stores; just make sure you pass all relevant references in those other stores into your gc
action.
This is an MST extension that takes an argument of the entity type that you will be storing in your reference pool.
1import { types } from "mobx-state-tree" 2import { withReferencePool } from "mst-reference-pool' 3import { PostModel } from "./post" 4 5const RootStore = types.model("RootStore", { 6 pool: types.array(PostModel) 7}) 8.extend(withReferencePool(PostModel))
This is an action on your extended store that adds an instance to the pool. If an instance already exists with that identifier in the pool, it will run applySnapshot
to the existing instance instead of making a duplicate. Think of it as an add or update action.
It will return the MST instance that it creates or updates.
1// ... 2.actions((store) => ({ 3 addPost(newPost) { 4 const post = store.addToPool(newPost) 5 // add reference to it somewhere? 6 store.posts.push(post) 7 store.currentPost = post 8 } 9}))
This is an action on your extended store that adds multiple instances to the pool. If an instance already exists with that identifier in the pool, it will run applySnapshot
to the existing instance instead of making a duplicate. Think of it as an add or update action for multiple items.
It will return an array of the MST instances that it creates or updates.
This is an action on your extended store that garbage collects instances in the pool that do not have any living references left.
You need to provide any references, since those could live anywhere on the tree. These can be single references or arrays of references.
I recommend creating a gc
action on your store that calls this action and passes in all references.
1.actions((store) => ({
2 gc() {
3 store.poolGC([
4 store.feed,
5 store.currentPost,
6 // perhaps some other store as well?
7 // search results is a common one
8 store.searchStore.filteredPosts
9 ])
10 }
11}))
This project is copyright 2021 by Infinite Red, Inc., and licensed under the MIT license.
No vulnerabilities found.
No security vulnerabilities found.