Comments (16)
Is there an example to nest stores?
For example, if I need all stores to be nested under one store.
const store = createStateLink({ settings: {...}, user: {...} }, dynamicStores: {})
function useWholeStore() {
return useStateLink(store)
}
function useSettingsStore() {
return useStateLink(store, l => l.nested.settings)
}
function useUserStore() {
return useStateLink(store, l => l.nested.user)
}
function useDynamicStore(id: string) {
return useStateLink(store, l => l.nested.dynamicStores.nested[id])
}
attach a store dynamically.
const state = useWholeStore() // PS: here it uses mounted state, but you can do the same outside of a React component using useStateLinkUnmounted
const id_for_new_store = Math.random().toString()
state.nested.dynamicStores.nested[id_for_new_store ].set({...})
something along these lines. Does it answer your question?
from hookstate.
Great to know that setting an object, then becomes actually a store by itself.
All is great. What is missing to me, is an example how to include methods relevant to substore. Is it with transform? So you will set dynamic store and then useStateLink to attach methods?
Ok, I get it, you actually attach methods inside you useUserStore() for example. But the what happens of you want to use it outside a component?
BTW by dynamic, I just mean attaching some known store at some stage and deleting it later. For example for dynamic component loading
from hookstate.
Is it with transform?
Yes, it is with transform. Example is here https://hookstate.js.org/global-getting-started-interface
So you will set dynamic store and then useStateLink to attach methods?
Yes, if you wish to add methods. I frequently use plain StateLink object it is fine for most of the cases.
But the what happens if you want to use it outside a component?
If you want to access the store outside of a component, use useStateLinkUnmounted
function. Example is here: https://hookstate.js.org/global-getting-started
This function returns the same StateLink object, which you can use to create, delete, update substores or any other segment of the data in the store. You can also apply transform the same way.
BTW by dynamic, I just mean attaching some known store at some stage and deleting it later. For example for dynamic component loading
It is easy. Have a look into the source code of this example: https://hookstate-example-app.netlify.com/ Two stores used here. They can be defined at completely different modules. They can be loaded separately. Hookstate StateRef is just a variable with subscribers on it's state, which can be managed the same ways as any other javascript variable.
Does it answer your question?
from hookstate.
I would like to do createStateLink({})
Then do .set({ someStore })
And add transform functions.
Essentially build a Store tree of Stores.
It is like with easy-peasy or mobx-state-tree.
And this store to be used in mounted or unmounted.
I have a thinking how to do it , but is not clear to me. There is also,
useUnmountedStateLink doesn't accept StateLink where useStateLink does accept it.
I think, I can do like this.
useStateLink(unmountedStateLink(createStateLink().nested.newStore.set({}), ()=>...))
from hookstate.
Correction
UserStore = unmountedStateLink(createStateLink().nested.set({ newStore }), ()=>...)
Outside of the component will use UserStore.
In a component:
useStateLink(UserStore)
Is it correct?
from hookstate.
The correct way would be as per the example I provided above. Sorry, mate, I am not sure I understand what you are trying to achieve. Could you please explain it a bit more?
from hookstate.
I am confused about this syntax
const transform = (s: StateLink<Task[]>) => ({
addTask = (t: Task) => s.set(tasks => tasks.concat([t]))
})
useStateLinkUnmounted(stateRef, transform).addTask({ name: 'Untitled' })
Vs this syntax
useStateLink(store, l => l.nested.user)
And looking at the code, how the first syntax returns the original statelink, it looks like it is overriden with the object...
from hookstate.
The first useStateLinkUnmounted(stateRef, transform)
returns an object, which has got a method addTask
. This object effectively wraps the original statelink by a custom interface, as a result, hides the details of the StateLink layout, and only return an object of type {addTask()}
.
The second useStateLink(store, l => l.nested.user)
also transforms the original statelink l
. It selects and returns only the nested user statelink. So, no new object is constructed, just part of a state is selected. It hides the fact that the returned statelink is a nested property of the store. Return type will be StateLink<User>
. You can extend this to something like the following:
// assuming User object has got property name of type string.
useStateLink(store, l => ({
getName() { return l.nested.user.nested.name.get() }, // or the same as l.get().user.name
setName(newName: string) { l.nested.user.nested.name.set(newName) }
}))
Return type of this call will be: { getName(): string, setName(name: string) }
It is up to you to wrap the StateLink by a custom store access interface or return the original StateLink without transform, or return nested StateLink with a 'select-like' transform function. If you develop a library and do not want to expose StateLink details, wrap by a custom store-access interface. Otherwise, it is up to you. You have got freedom of choice here.
from hookstate.
More explanation:
The following
function MyComponent() {
const stateAccessInterface = useStateLink(store, transform)
....
}
Is the same as:
function MyComponent() {
const statelink = useStateLink(store)
const stateAccessInterface = transform(statelink)
....
}
transform
function can be anything, which receives statelink and returns anything.
There are 2 cases where the first option of applying the transform (i.e. as a second argument) is the only option. The first case is when you want to use StateMemo
transform function. Read about it in the docs. It is essentially for additional performance improvement, which you might not always need. The second case when you apply the transform not at the useStateLink
call but earlier, i.e. when you create the original Store object. For example:
const Store: StateInf<{ getName(): string, setName(name: string): void }> = createStateLink({ user: { name: 'Bob' } }, l => ({
getName() { return l.nested.user.nested.name.get() }, // or the same as l.get().user.name
setName(newName: string) { l.nested.user.nested.name.set(newName) }
}))
const userStateAccessInterface = useStateLinkUnmounted(Store) // will return your custom access interface straight away
userStateAccessInterface.setName('John')
function MyComponent() {
const userStateAccessInterface = useStateLink(Store) // will return your custom access interface straight away
return <input value={userStateAccessInterface.getName()} onChange={e => userStateAccessInterface.setName(e.target.value)} />
}
from hookstate.
Got you
from hookstate.
So the createStateLink doesn't create stateLink or is it? It seems to create stateRef.
Can I then use the linkstate from useUnmountedStateLink in useStateLink?
ref = createStateLink({})
s = useUnmountedStateLink(ref)
s.nested.user.set({})
User = s.nested.user
User.notReservedMethod = () => doSomething(User)
useStateLink(User)
from hookstate.
So the createStateLink doesn't create stateLink or is it?
You are right. I see there is a confusion. Names are probably for historical reasons. In fact, StateRef<S>
is the same as StateInf<StateLink<S>>
. It means createStateLink<S>(v)
returns StateInf<StateLink<S>>
, and createStateLink<S, R>(v, transform: (l: StateLink<S> => R))
returns StateInf<R>
. It means better name for createStateLink
is actually createStateInf
.
useStateLinkUnmounted
is deprecated on master and replaced by easier to use and warning free alternative - access method of StateInf
: StateInf<R>.access(): R
. R
can be StateLink<S>
, if transform is not applied or returns StateLink
instance.
useStateLink
either:
- accepts
StateInf
and returns the observed version ofStateInf.access()
result, - accepts
StateLink
(and optional transform) and returnsStateLink
(or optionally transformed StateLink) pointing to the same data, but observed differently for scoped state updates for performance - or accepts
initialValue
(and optionaltransform
) and returnsStateLink
(or result of the optional transform of the StateLink) - internally it creates the analogy ofStateInf
from the initialValue.
So good name for useStateLink
is probably useStateInf
. I am also thinking, it can be named just useState
(and createStateLink
could be named just createState
, and StateInf
just State
), but I am a bit concerned about the conflict with React.useState
. Alternative combo is StateInf -> Store
, useStateLink -> useStore
and createStateLink -> createStore
, but I am not sure if the name implies that Store is global. It is not always global, useStateLink can auto-create local state as per 3) above. What do you think is the best combo names?
Can I then use the linkstate from useUnmountedStateLink in useStateLink?
As per 2) above, type system will allow you do so, but it does not make sense and will not give you the expected result. Non-transformed result of useStateLinkUnmounted
returns StateLink
which does not observe state changes. It will still always return you the latest state data when you use it, but it will not react on state changes. It means the derivative of it, like useStateLink(useStateLinkUnmounted(Store))
will not trigger re-render of you component.
The correct way is:
GlobalStore = createStateLink({ user: {}})
UserStore = GlobalStore.wrap(l => l.nested.user) // you can wrap by a custom state access interface, like we discussed above
useStateLinkUnmounted(UserStore).set({ /* new user data */ })
// in the coming version, it will be UserStore.access().set(...)
function MyComponent() {
const userState = useStateLink(UserStore)
userState.get().name // example
}
// setting props of the StateLink or StateLink.value is not correct,
// it will either throw or is not observed by components for rerender.
// Always use set() method (or coming merge) to mutate the data in the state
User.notReservedMethod = () => doSomething(User) // <!-- do not do this
Hope it helps.
from hookstate.
It helps, thanks!
from hookstate.
What do you think about names to remove the confusion?
from hookstate.
createStore and useStore are good names.
Because can be many global stores, it is explicit enough to write useStore (someGlobalStore).
But maybe it is wise to differentiate
useStore
useFeatureStore
useLocalStore
from hookstate.
from hookstate.
Related Issues (20)
- Any showcase how to work with Immutables? HOT 2
- Resource leak with `useHookstate` HOT 2
- Is this lib still being updated? HOT 3
- Request: throw error when trying to assign nested state to a Proxy object HOT 2
- Migration from 3 to 4 HOT 4
- Localstored - optional initializer HOT 1
- https://hookstate.js.org/docs/exceptions/#hookstate-106 is killing me HOT 1
- What is the meaning of `E` in State<S, E>? HOT 1
- Injecting React-Router-dom instance into the store HOT 1
- one of my favourite projects really HOT 4
- More than 5 extensions loading HOT 2
- Creating a global object using hookstate, but unable to find the property when using it. HOT 2
- How to handle file objects in v4? HOT 1
- Isolating global states between tests HOT 4
- state.attach is not a function
- Combine extensions HOT 3
- Nextjs: localstorage is not defined HOT 6
- having problem with getting rid of proxy HOT 2
- Broadcasted state extension not working HOT 2
- 106 EXCEPTION 'Cannot Convert Undefined Value to Object' Error when setting and getting global store state in two seperate components HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from hookstate.