-
-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
useStoreListener hook #2
base: main
Are you sure you want to change the base?
useStoreListener hook #2
Conversation
6b7b6ae
to
dea7127
Compare
The origin idea of Nano Stores is to move logic from React components. In general, I see the nanostores’s way to solve this task in: import { listenKeys } from 'nanostores'
function bindAnotherAction () {
const unbind = listenKeys(myStore, ['field'], value => {
if (value.field === 'satisfies-some-condition') {
triggerAnotherAction()
}
})
return unbind
}
function MyComponent() {
useEffect(bindAnotherAction)
} Do you have reasons to do have this logic in React component? |
I think this is more of a idealistic vs pragmatic approach I.e. in a perfect world it might be a good practice to make sure that no local component logic interferes with logic that is handled by the stores (outside react) In practice, we just wanna be able to do stuff and have the tools that help us. Extracting |
OK, let’s add tests and docs. I agree that sometimes people may want old approach. |
dea7127
to
16ffa43
Compare
Hi again! I'm not sure whether the If everything's fine the next thing to do is to update the docs |
@@ -40,6 +40,30 @@ export function useStore< | |||
? Pick<StoreValue<SomeStore>, Key> | |||
: StoreValue<SomeStore> | |||
|
|||
type Listener<SomeStore extends Store> = ( | |||
value: StoreValue<SomeStore>, | |||
changed?: SomeStore extends MapStore ? StoreValue<SomeStore> : never |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this parameter only have a value if the store is map
store?
And what is its value if the store value is a primitive?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this parameter only have a value if the store is map store?
Yeap
And what is its value if the store value is a primitive?
In this case you do not have store.setKey
and we have no easy way to detect changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well I was asking because of this: https://github.com/nanostores/react/pull/2/files#r744618456
index.js
Outdated
React.useEffect(() => { | ||
let listener = (value, changed) => listenerRef.current(value, changed) | ||
if (opts.leading) { | ||
listener(store.get(), null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it correct to pass null
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is better to call listener(store.get())
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, thanks!
16ffa43
to
a37b553
Compare
LGTM. Do you want to add anything else? |
Great, thanks! |
Let’s update docs in this PR |
@@ -32,3 +32,31 @@ export function useStore(store, opts = {}) { | |||
|
|||
return store.get() | |||
} | |||
|
|||
export function useStoreListener(store, opts = {}) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is worth moving the new hook into a separate file: this way it will not affect those who do not need it.
} | ||
}, [store, '' + opts.keys, opts.leading]) | ||
|
||
return null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the return does nothing, it seems it can be removed.
Motivation:
A common pattern is to react to some store change in an effect:
While this does the job, unfortunately it makes the whole component re-render when store changes, even if the
field
doesn't yet satisfy our condition.Solution here would be to create a hook that is designed to only trigger effects and not interfere with the render phase:
That way, we can use the familiar effect pattern, but avoid unwanted re-renders and calls of other hooks in the component
If you decide this is a good feature, I'll finish the pull request by updating types, tests and docs, thanks!