Skip to content

Add usePresence for solid primitives#549

Open
matfire wants to merge 12 commits into
automerge:mainfrom
matfire:solid-primitive-add-usepresence
Open

Add usePresence for solid primitives#549
matfire wants to merge 12 commits into
automerge:mainfrom
matfire:solid-primitive-add-usepresence

Conversation

@matfire

@matfire matfire commented Jan 17, 2026

Copy link
Copy Markdown
  • Adds a usePresence hook to the solid-primitives package (mimics the one present in the react-hooks package)
  • Exposes start/stop methods from the underlying Presence instance

@chee chee self-assigned this Jan 17, 2026
@matfire matfire marked this pull request as ready for review January 19, 2026 10:42
@msakrejda

Copy link
Copy Markdown
Collaborator

Thanks for the contribution!

FYI, @neftaly suggested also exposing start/stop; I'm doing that in #544. He also suggested being able to change the update interval. Right now, you can do that by starting and stopping, but the React hook does not expose that. I'll take a look at incorporating that, and it would probably make sense here as well.

@matfire

matfire commented Jan 19, 2026

Copy link
Copy Markdown
Author

Hey,

Thanks for the feedback! I'll add those parameters asap.

@matfire

matfire commented Jan 20, 2026

Copy link
Copy Markdown
Author

hey @msakrejda, quick question: when you mention the update interval you're talking about the heartbeatMs attribute in the Presence class, right? Or am I missing something?

@neftaly

neftaly commented Jan 27, 2026

Copy link
Copy Markdown
Collaborator

@matfire I think so. I want to be able to have a peer declare itself as connected, but be idle or in low-power mode. Eg, a phone trying to optimize battery/radio use, or clients optimizing sync server bandwith.

@matfire

matfire commented Jan 27, 2026

Copy link
Copy Markdown
Author

then it should already be implemented, I think. You can pass in both the heartbeat rate & the peer ttl in the initial hook definition and in the exposed start method. is there something more that's needed than that ?

@neftaly

neftaly commented Jan 28, 2026

Copy link
Copy Markdown
Collaborator

Can I trivially switch between fast and slow heartbeat rate, while the app is running? If this can be done just by changing a prop or arg then it should be good. I am very unfamiliar with these codebases :)

@neftaly

neftaly commented Jan 28, 2026

Copy link
Copy Markdown
Collaborator

Aside, It may also be useful to have a way to force a heartbeat. But I don't need this feature atm.

@matfire

matfire commented Jan 28, 2026

Copy link
Copy Markdown
Author

mmh, I don't think the Presence class exposes just changing the heartbeat, so you would still need to stop & start the reference with a different heartbeat (doable in the current state of the pr). Or I'd need to modify the Presence class directly by adding a setter for the heartbeat (and handle restarting the timer for it etc); this would also imply updating the react usePresence hook to keep feature parity

@msakrejda

Copy link
Copy Markdown
Collaborator

I think it's okay to require starting / stopping Presence to adjust heartbeat intervals. Starting / stopping is pretty lightweight and can be done with no visible impact to the Presence state (I think). I don't think it's worth complicating the API to support adjusting heartbeats while presence is running. Support for forcing heartbeats also seems pretty niche...

@msakrejda

Copy link
Copy Markdown
Collaborator

hey @msakrejda, quick question: when you mention the update interval you're talking about the heartbeatMs attribute in the Presence class, right? Or am I missing something?

Sorry I missed that: yeah, just the heartbeat interval.

@matfire

matfire commented Jan 31, 2026

Copy link
Copy Markdown
Author

hey @msakrejda, quick question: when you mention the update interval you're talking about the heartbeatMs attribute in the Presence class, right? Or am I missing something?

Sorry I missed that: yeah, just the heartbeat interval.

then we're good to go 👍

@neftaly

neftaly commented Feb 1, 2026

Copy link
Copy Markdown
Collaborator

A test for the switching scenario would be really nice :) I'll make an issue

@matfire

matfire commented Feb 1, 2026

Copy link
Copy Markdown
Author

Got it!

Since there's a separate issue, should the tests be in a separate pr or (at least for solid) is it fine to add it in here ?

@neftaly

neftaly commented Feb 1, 2026

Copy link
Copy Markdown
Collaborator

It's fine to add them to this PR. i don't know if there should be separate tests for solid and react, if so please add a note about missing react tests to the issue.

@neftaly

neftaly commented Feb 2, 2026

Copy link
Copy Markdown
Collaborator

Should we test something like <Component heartbeatMs=${ms} />? So that we're testing both the imperative api and the immutable api

@matfire

matfire commented Feb 9, 2026

Copy link
Copy Markdown
Author

added a few more tests to also set a custom heartbeat on "mount"

Comment on lines +40 to +42
const [presence] = createSignal(
new Presence<State>({ handle, userId, deviceId })
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't think we get anything from this being a signal, as it isn't tracking and doesn't change.

)
}

onMount(() => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onMount is a non-tracking function that runs in an effect, i think for our purposes the behaviour will be essentially the same if we move the body of it out to the top level of usePresence

@chee

chee commented Feb 11, 2026

Copy link
Copy Markdown
Collaborator

this looks good, i left a couple comments

@matfire

matfire commented Feb 12, 2026

Copy link
Copy Markdown
Author

thanks for the feedback @chee, fixed it; let me know if this is what you meant

@msakrejda

Copy link
Copy Markdown
Collaborator

Does this need updates for the PeerStateView changes in #555? I thought it might at first, but now I think it's fine, though I'm not 100% sure. Could you rebase on top of those changes?

@matfire

matfire commented Feb 19, 2026

Copy link
Copy Markdown
Author

updated the fork, tests still seem to pass

}: UsePresenceConfig<State>): UsePresenceResult<State> {
const [localState, setLocalState] = createStore<State>(initialState)
const [peerStates, setPeerStates] = createStore(new PeerStateView<State>({}))
const presence = new Presence<State>({ handle, userId, deviceId })

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So after #555, the Presence constructor no longer takes userId or deviceId arguments. Handling aggregation by user, device, or other higher-level concept is done at read time.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it, will update ASAP

@msakrejda

Copy link
Copy Markdown
Collaborator

Thanks for the update, @matfire. @chee (or anyone else), any other feedback?

@msakrejda

Copy link
Copy Markdown
Collaborator

Any reason not to merge this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants