4.0 - custom store?
etodanik opened this issue ยท 6 comments
It could be idea to not work with a "built-in" store but rather to provide an adapter that satisfies a certain interface, with functions like getHex
, e.t.c
In our example - we have an already existing state for the hex that travels through network, and it is an unnecessary chore to keep converting back / forth - and we don't wanna store our state on the honeycomb
and have it manage that.
Would you consider detaching the state and allowing clients to provide it via adapters or something?
I don't quite understand what you mean. First of all, which version are you using? In the latest alpha (v4.0.0-alpha.5
) Grid
indeed has a "store": a Map
. In the latest version of the next
branch, Grid
also has a Map
that stores the hexes.
In either version, Grid
fulfils two functions: a container for hexes and methods "to do things with those hexes" (mainly iterating and querying). Do you want a way to "to do things with those hexes" but not be a container for those hexes? Could you share some code to clarify your request?
For what it's worth: Grid
also has fromJSON()
and toJSON()
methods that should make it easier to (de)serialize a grid. Assuming that's what you mean by "that travels through network".
Finally, I'm about to merge another big change into the next
branch. It should be the last big change for now. I want to focus on writing tests and documentation to get v4 released.
Yes, I'm using your latest commit, always ;) I love danger. So when you see me talk about anything, it's always with the latest commits.
So, I think of it like the mental model of working with "history" in react-router
or a store adapter in any caching library. In the 'history' example, you have a History API that has methods like pop(), push() and others. If you're prototyping you're probably gonna use a default browserHistory
adapter, but say if you want to integrate your routing into a more complex model - you'd provide your own adapter that satisfies all these method signatures and do more advanced things with it like logging, synchronising your history state with the global app state, plugging routing into an event sourcing or redux model e.t.c
Same thing with cache, you normally start with something like memoryStore
in most models, and then you'd replace it with your own - it could be a more advanced memoryStore
, it could be something that later goes to redis
, e.t.c e.t.c
With honeycomb
- we already have a store for the hexes in Redux. That store could get manipulated by actions in a reducer.
Of course, yes - we could "live" with constantly serialising (toJSON()
) and deserialising (fromJSON()
) our data... Right now actually to avoid having this persistent store do createGrid() from scratch any time we want to work on it .... But a more elegant way feels like having something that we supply to createGrid()
that has all the required methods (getHex()
, e.t.c e.t.c) and we implement to conveniently and directly re-use the Redux global store to read from the grid, instead of having to constantly go back & forth.
By the way, I'm more than willing to create a PR for that and write tests e.t.c, if conceptually you're OK with the idea but don't have time / desire to implement it yourself just yet.
This pattern of working with a library (providing an adapter, with a simple very basic "in-memory" adapter provided by default) works really well for a lot of libs that are very heavily used and has always been very good DX.
Yes, I'm using your latest commit, always ;) I love danger. So when you see me talk about anything, it's always with the latest commits.
๐ Great!
I see what you mean. Wouldn't extending Grid
be what you need? Something like this:
// this would be your custom store
interface Store<T extends Hex> {
hexes: IterableIterator<T>
getSize(): number
find(coordinates: HexCoordinates): T | undefined
}
class CustomGrid<T extends Hex> extends Grid<T> {
get size(): number {
return this.#store.getSize()
}
[Symbol.iterator]() {
return this.#store.hexes
}
#store: Store<T>
constructor(hexClass: HexConstructor<T>, store: Store<T>) {
super(hexClass)
this.#store = store
}
getHex(coordinates: HexCoordinates): T | undefined {
return this.#store.find(coordinates)
}
}
I could make an interface to make it more clear what properties your CustomGrid
(which doesn't have to be a class) should implement. Something like this:
// there should probably be more properties than these:
interface HexStore<T extends Hex> {
readonly size: number
[Symbol.iterator](): IterableIterator<T>
getHex(coordinates: HexCoordinates): T | undefined
}
class CustomGrid<T extends Hex> implements HexStore<T> {
// ...
}
// or:
function createGrid<T extends Hex>(store): HexStore<T> {
// ...
}
Would that meet your needs?
Yup, this works! An interface + a "blessed" way to do it would be exactly the answer.
I added these interfaces. Please let me know if this works for you.
๐ This issue has been resolved in version 4.0.0-beta.1 ๐
The release is available on:
Your semantic-release bot ๐ฆ๐