Skip to content

Instantly share code, notes, and snippets.

@mfbx9da4
Last active March 6, 2022 19:44
Show Gist options
  • Save mfbx9da4/4eede24c70d0669ddd5f96bdd2e8416d to your computer and use it in GitHub Desktop.
Save mfbx9da4/4eede24c70d0669ddd5f96bdd2e8416d to your computer and use it in GitHub Desktop.
Github issue realm-js flatlist + listener
import React, { useEffect, useLayoutEffect, useState } from 'react'
import { FlatList, SafeAreaView } from 'react-native'
import RNFS from 'react-native-fs'
import Realm from 'realm'
export function App() {
const r = useWaitForRealm()
const [initialized, setInitialized] = useState(false)
useEffect(() => {
if (!r) return
const asyncEffect = () => {
// Cleanup the db
const fooResults = realm.objects<Foo>('foo')
realm.write(() => {
for (const x of fooResults) {
realm.delete(x)
}
realm.create<Foo>('foo', { id: '-1' }, Realm.UpdateMode.Modified)
})
setInitialized(true)
}
void asyncEffect()
}, [r])
if (!initialized) return null
return <FooList />
}
let i = 0
const sleep = (milliseconds: number) => new Promise(r => setTimeout(r, milliseconds))
function FooList() {
const fooResults = useQuery<Foo>(() => realm.objects<Foo>('foo'))
useEffect(() => {
const asyncEffect = async () => {
while (i < 30) {
const id = String(i++)
console.log('Start write 1, id:', id)
await sleep(10)
realm.write(() => {
realm.create<Foo>('foo', { id }, Realm.UpdateMode.Modified)
})
await sleep(0)
console.log('start write 2, id:', id)
realm.write(() => {
realm.create<Foo>('foo', { id }, Realm.UpdateMode.Modified)
})
}
}
asyncEffect().catch(console.error)
}, [])
return (
<SafeAreaView style={{ margin: 20 }}>
<Text>{fooResults?.length}</Text>
{/* {fooResults?.map((_, index) => (
<Message index={index} />
))} */}
<FlatList
inverted
data={fooResults}
renderItem={x => <Message index={x.index} />}
keyExtractor={item => item.id}
maintainVisibleContentPosition={{ minIndexForVisible: 0, autoscrollToTopThreshold: 500 }}
/>
</SafeAreaView>
)
}
function Message({ index }: { index: number }) {
console.log('Message', index)
const x = useObject<Foo>('foo', '-1')
return <Text>{x?.id}</Text>
}
// #region === Setup the Realm instance (start) ===
// You can skip reading this bit, I've left it here so it can be easily reproduced.
const FooSchema: Realm.ObjectSchema = {
name: 'foo',
primaryKey: 'id',
properties: {
id: 'string',
},
}
export let realm: Realm
let realmInitializingPromise: Promise<Realm> | undefined
export function waitForRealm() {
if (realm) return Promise.resolve(realm)
if (!realmInitializingPromise) realmInitializingPromise = initRealm()
return realmInitializingPromise
}
async function initRealm() {
const path = `${RNFS.CachesDirectoryPath}/example.realm`
realm = await Realm.open({
path,
schema: [FooSchema],
schemaVersion: 0,
})
return realm
}
export function useWaitForRealm() {
const [optionalRealm, setRealm] = useState<Realm | undefined>(realm)
useEffect(() => {
waitForRealm()
.then(x => setRealm(x))
.catch(console.error)
}, [])
return optionalRealm
}
type Foo = { id: string }
export function useObject<T>(type: string, primaryKey: string): (T & Realm.Object) | undefined {
const [object, setObject] = useState<(T & Realm.Object) | undefined>(
realm.objectForPrimaryKey(type, primaryKey)
)
useEffect(() => {
const listenerCallback: Realm.ObjectChangeCallback = (_, changes) => {
if (changes.changedProperties.length > 0) {
setObject(realm.objectForPrimaryKey(type, primaryKey))
} else if (changes.deleted) {
setObject(undefined)
}
}
if (object !== undefined) {
object.addListener(listenerCallback)
}
return () => {
object?.removeListener(listenerCallback)
}
}, [object, type, primaryKey])
return object
}
function useQuery<T>(query: () => Realm.Results<any>) {
const [collection, setCollection] = useState<Realm.Results<T>>(query())
useEffect(() => {
const listenerCallback: Realm.CollectionChangeCallback<T> = (_, changes) => {
const { deletions, insertions, newModifications } = changes
if (deletions.length > 0 || insertions.length > 0 || newModifications.length > 0) {
setCollection(query())
}
}
if (collection && collection.isValid() && !realm.isClosed)
collection.addListener(listenerCallback)
return () => {
collection?.removeListener(listenerCallback)
}
}, [collection])
return collection
}
// #endregion === Setup the Realm instance (end) ===
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment