-
Notifications
You must be signed in to change notification settings - Fork 38
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
Watch - high-performance replacement for subscribe() #1010
Comments
I think the
For me having the access to an imperative API via the experimental watch was great not only due to performance characteristics, but also due to the flexibility of the API. |
Good point @KeKs0r - thanks for the feedback. |
Somewhere along the line we lost the fact that when |
curious about what stage this is at I'm currently debating between replicache and rxdb and this is the feature that it's coming down to |
We actually already have experimentalWatch: https://doc.replicache.dev//api/classes/Replicache. It’s deployed in current release. The new api will be a superset of this so you can start using it now. |
// ./states/tasks.js
import { ref } from 'vue'
import { Replicache } from 'replicache'
import { id as newId } from '@rnvf/id-generator'
export const taskList = ref(new Map())
const rep = new Replicache({
// eslint-disable-next-line no-undef
licenseKey: import.meta.env.VITE_REPLICACHE_LICENSE_KEY,
name: `tasks`,
pushURL: '/api/tasks/push',
pullURL: '/api/tasks/pull',
mutators: {
async addTask(tx, task) {
const id = newId('task')
await tx.put(`task/${id}`, { ...task, id, done: false })
},
async toggleTask(tx, task) {
await tx.put(`task/${task.id}`, { ...task, done: !task.done })
},
async removeTask(tx, task) {
await tx.del(`task/${task.id}`)
}
}
})
/**
* stable but rerenders whole list (on each change)
*/
rep.subscribe(async (tx) => tx.scan({ prefix: 'task/' }).entries().toArray(), {
onData(data) {
// used for initial load only
if (taskList.value.size <= 0) {
taskList.value = new Map(data)
}
}
})
/**
* experimental but rerenders only changed items
*/
rep.experimentalWatch(
(diff) => {
for (const { op, key, newValue } of diff) {
if (op !== 'del') {
taskList.value.set(key, newValue)
} else {
taskList.value.delete(key)
}
}
},
{
prefix: 'task/'
// initialValuesInFirstDiff: true // might have performance impact, too
}
)
export const addTask = rep.mutate.addTask
export const removeTask = rep.mutate.removeTask
export const toggleTask = rep.mutate.toggleTask only one thing left for testing: Is |
Very cool @mashpie - is there anything missing from watch for your use in Vue? |
Thanks @aboodman - so far I don't miss anything but time to play and setup further examples ;) |
Replicache UIs are currently built using the
subscribe()
method.The idea of subscribe is that it is an arbitrary function of a Replicache state that can return any
JSONValue
as a result. Since it is an arbitrary function there's a limit to how far it can be optimized. For example, the overwhelmingly most common subscription is just getting all entries with a particular key prefix:We can optimize this subscription to only run when one of the accessed keys is modified (and we do currently do this). But since we can't know what the function does with that data, we are forced to run the function again each time it is invalidated, in its entirety.
This sucks since in this common case, Replicache knows how those keys changed and so it could in theory fix up the returned data surgically without re-running the scan.
We plan to support this common use case efficiently by introducing a new
watch()
method that looks something like:The text was updated successfully, but these errors were encountered: