Closed L3V147H4N closed 3 years ago
I have the same Error!. It seems that if you pass an object to navigation, delete this object (while the object is still in the navigation stack), - it will trigger this error. I found it is working if I pass an id, retrieve again the object on the navigated view and then make the deletion. But this is sure not the right solution...
I have the same Error too.situation : React Native Android ,Navigation ,delete the object,when click back,error happen.
I have the same situation in iOS.
I have the same error :(
+1 same error
You need to use Realm.open
and you'll need to query for the object you want to delete.
Also it's a good idea to separate your realm code from your presentation code, see discussion here.
This is how I'm using realm to dispatch a redux action using redux-thunk
.
const retriveSettings = () => (dispatch) => {
return Realm.open({
schema: [SettingsSchema],
schemaVersion: SettingsSchema.schemaVersion
})
.then(realm => {
const settings = realm.objects('Settings').find(({ id }) => (id === 0));
dispatch({
type: types.RETRIEVED_SETTINGS,
settings
});
})
.catch(e => console.log(e));
}
Any chance to check this one? Otherwise, it's a massive refactor...
I found what I was a mistake. After removal of the Realm Object, I have not updated the store and apply to him on the screen where I had this error. That is, the problem was that I apply to already remote data. I solved the problem, just updating the store after deleting the Realm Object. Perhaps someone it will be useful.
I had this issue as wel. The reason why was that I was referencing to an object of the Realm DB in a list view. In my particular case the solution was creating a clone of the object to use in the list:
Object.assign({}, realmObject);
This way when a row was deleted all references within the row pointed to that cloned object instead of an object from realm that did not exist anymore.
Maybe this is of some use for someone ;)
+1
in your schemas, extend them with Realm.Object
. You can then call object.isValid()
to check if the object still exists in realm.
see example here
isValid()
also not work...
how to resolve this problem? had the same error
Wasted everyone's time in the last couple of days with this bug which was getting wrapped in another error in our codebase. Any fixes in sight?
same error !
resolved my issues, just make sure the Realm object not loading from Redux store after deleted then it will be fixed.
same error ! I delete one then query all, red box~
resolved this error, just do not filter array of RealmObject, I convert each RealmObject to PlainObject, and it works well.
@vance-liu 你好,convert each RealmObject to PlainObject 如何实现?可以贴一下代码吗?被这个问题困扰好久了~
Thanks all, I make the copy of the Realm array object, so I did well. Maybe it has links between realm objects. Can you guys explain more for me? I have just do with ReactNative for 2 months.
@inspireui Can you please elaborate on how you resolved your issue?
resolved my issues, just make sure the Realm object not loading from Redux store after deleted then it will be fixed.
I have several detail views of the opened realm object loaded in scenes from react-native-router-flux.
When objected being viewed is deleted I can find no way to get these detail views to gracefully release the deleted the object to prevent a crash no matter how many try catch blocks I add to the detail view scene.
I feel like to avoid a crash I must mark it for deletion and then actually delete it when I know no views are referencing it.
We're almost celebrating this bug it's first birthday, and from the number of people involved here, it seems like it cost a lot of us hours of investigation, with no elegant solution. Is there any chance this one will be solved? 10x!!!
@EyalSi More then a year (yay), so to solve the problem here I did this:
export const listTasks = (start=0, take=10) =>
new Promise((resolve, reject) => {
Realm.open(config)
.then(realm => {
let tasks = realm.objects(TASK_SCHEMA).slice(start, start+ take );
resolve(tasks.map(task=>({
...task
})));
})
.catch(error => reject(error));
});
So doing tasks.map(task=>({ ...task })));
transform the realm objects in plain objects
Now when I delete the object from the realm it wont give the Accessing object of type X which has been invalidated or deleted
error.
Another way to avoid the error is using a listener in the filtered realm, so when you delete your objects will be updated. But I was having performances issues with huge lists so I had to paginate the records.
let arrayResults = Array.form(realmResults)
plainResults = JSON.parse(JSON.stringfy(results)) // array
Duplicating the object will result in performance degradation. Hopped to get a fix in realm.
For me the array transformation does not work.
people() {
const people = realm.objects('Person').filtered('name != $0', null);
setTimeout(() => {
realm.close();
}, 100);
return Array.from(people);
}
setTimeout
I get: Error: Access to invalidated Results objects
, why? And what time could be chosen wisely?Accessing object of type Person which has been invalidated or deleted
What can I do in order to continue working?
I came up with a solution, if you are using react-navigation along with redux and realm, you could simply reset the state of react-navigation like this:
import { NavigationActions } from 'react-navigation'
const resetNavigationState = (navigation, routeName = 'Login') => {
const resetAction = NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: routeName })
]
})
navigation.dispatch(resetAction)
}
routeName is the stack's navigator screen where you want to go, for example if I want to reset the state and go to HomePage screen, I do something like this:
resetNavigationState(this.props.navigation, 'HomePage')
In Node.js, I could "PATCH" the issue with below given code.
const genreJsonString = JSON.stringify(genre);
genreRealm.write(()=>{
genreRealm.delete(genre);
});
resp.send(JSON.parse(genreJsonString));
@lossen how do we reset the redux store ? I created a dispatch action (I'm using redux-saga) to "reset" the state to its initial state but still got this error. I followed this.
I've gotten this error a few times but cant get it to reliably repeat. Can anyone confirm this only happens in debug builds, not release? Obviously on release we wouldn't get the warning, just failure.
Same issue here. I'm writing an object to realm and it's visible via Realm Studio. So it's definitely persisted. Then when fetching the Objects of the Model, each value of each model ist "Accessing object..." like the error message. The objects were loaded once in development. Since then, it didn't work anymore. No code changes in between...
This is how I solved this problem -
First I created a function in my utils package -
export function convertToArray(realmObjectsArray)
{
let copyOfJsonArray = Array.from(realmObjectsArray);
let jsonArray = JSON.parse(JSON.stringify(copyOfJsonArray));
return jsonArray;
}
Then, I used it to query Realm -
...
let allServicePlans = realm.objects(ScheduleSchema.name);
allServicePlans = convertToArray(allServicePlans);
return allServicePlans;
...
Haven't noticed any performance issues till now, and have also gotten rid of that error for now it seems.
@kunalqss Could you try just this to see if it works for you?
let allServicePlans = realm.objects(ScheduleSchema.name);
return allServicePlans.map(service=>({ ...service })));;
same error
@lodev09 Thank you for the example on how to extend my class
class Car extends Realm.Object {
I can now call isValid() on my object.
Unfortunately isValid() always returns true.
Still trying to find a solution to app crashes when referencing invalidated or deleted Realm objects.
@esutton it shouldn't return true
if the object is not valid e.g. deleted from realm
try
if realmobject.isInvalidated { }
I still issues, how to resolve it?
Hi, there. IMO this is not a Realm issue, because it's just a mutable object being passed around as a prop and being deleted. One of the first things a new developer using Realm will do is fetch data, save it in Realm and pass it through props to another component as a master/detail. It's pretty obvious he's going to use navigation too and he won't have any idea this will break.
I don't know if there's a best practice for this case yet and I use Realm for about three years 🤔 What should we do?
JSON.parse(JSON.stringify(object))
or Object.assign
? (this is error prone)Related issues: #394, #443, #1671, #2091
@tgoyne @cmelchior @kraenhansen @kneth Sorry about the flood. Just trying to raise attention.
I have a lot of doubts about using realm.js with react-native. I agree it is fast as a lightning. But speed is not everything. Realm mutates its data (which doesn't play well with react), its listeners don't give you a lot of information about data changes (so you would maybe update your state/store using some immutable way), it messes a lot with chrome debugging and making it useless and finally this issue. I don't see a benefit of realm other than its speed. I made a demo by using realm vs TypeOrm + SQLite and yep, realm was faster. But when you use TypeOrm the right way, it really comes close to realm.
Using realm for a complex react-native project can become a million dollar mistake easily. You can't debug it (they say it works with Safari but a lot of people use Google Chrome, react-native-debugger etc.), it becomes so unpredictable because of mutations, you just try to understand what is going on by using console.warn
or react-native log-android
.
I think realm should have a package to integrate with react. Like mobx does. Or react-redux. Or react-apollo. They integrate your react components with the library itself. And that's it. You don't have to worry about that anymore. All the complex things to handle just abstracted away from you.
I really don't understand how so many people and blog posts just recommend realm for react-native and don't show you a good way to handle data mutations, debugging etc.
react-realm-context may look like a good package. We are using a mildly modified version of it. It definitely eases a lot of hard work for you. But this issue still stands there.
Anyway, when we come to this problem, I think using JSON.parse(JSON.stringify(...))
may cause a lot of performance problems. It may cause a lot of unnecessary re-renders. And you know, react-native needs some performance optimizations and best practices to handle complex components or lists. Or it might cause much more problems.
We are using some kind of a soft delete
way. We don't delete any record from realm. We create each table with a __isDeleted
field. When we delete a record, we just flip its value to true
. Just filter them to not show on screens. Don't post them to your APIs. You can choose some time (like the initialization of the application) to really delete these soft deleted records.
We are using a mildly modified version of it. It definitely eases a lot of hard work for you. But this issue still stands there.
@onderonur: I would love to know what mild modifications you've made, what would make the react-realm-context package better. We would love upstream PRs too :)
We are using a mildly modified version of it. It definitely eases a lot of hard work for you. But this issue still stands there.
@onderonur: I would love to know what mild modifications you've made, what would make the react-realm-context package better. We would love upstream PRs too :)
Actually, I don't think our modifications will be useful for the package itself :)
Like I said, we simply use a flag for deleted items. And we are always checking if the __isDeleted
field is true or false. So instead of doing it on every single query component, our base query component filters them by default. And we added a component called "garbage cleaner" to wipe these soft deleted records out at a particular time like initialization of the app.
An additional and useful component is QueryById
. It simply gets a type
and a id
prop to return a single record. It just wraps the Query
component, you know. But it is something we use very often.
On of the changes was, we are still using the RealmProvider
, but we initialize realm as a singleton and pass it to the provider. Like Provider
of react-redux
. We wanted to use the realm instance in places like redux action creators etc. Accessing it through the provider is a great pattern inside components. But rather than passing the realm instance as a parameter to external functions, we just wanted to use a singleton.
This might have a lot of side-effects for some cases. I wouldn't recommend to add this to the package itself. It is just something useful for our cases :)
Even though the
.isValid
method is present in both collection and object, neither of them is doing anything to prevent this error.I tried using Collection.isValid, Object.isValid, Results.snapshot .. nothing works
I'm rendering the Results on one view and if I delete one Object in another view and then return it throws this error.
here is my code for the 2 views
import React, { Component } from 'react'; import { InteractionManager } from 'react-native'; import { Body, Button, Container, Content, Fab, Footer, FooterTab, Header, Icon, Input, Item, Left, List, ListItem, Right, Text, Title, View } from 'native-base'; import realm from '../realm'; class CharactersScreen extends Component { constructor (props) { super(props); this.characters = realm.objects('Character'); this.state = { searchBar: { active: false }, characters: this.characters }; } navigateToAddCharacter = () => { let { navigate } = this.props.navigation; navigate('AddCharacter'); } static navigationOptions = { title: 'Characters', headerRight: <View style={{ flexDirection: 'row' }}> <Button transparent><Icon name="md-search"/></Button> <Button transparent><Icon name="md-funnel"/></Button> </View> } listenToRealm = (name, changes) => { this.setState({ characters: this.characters }); } componentWillMount () { InteractionManager.runAfterInteractions(() => { this.characters.addListener(this.listenToRealm); }); } componentWillUnmount () { this.characters.removeListener(this.listenToRealm); } render () { let { navigate } = this.props.navigation; let { searchBar, characters } = this.state; return ( <Container> { searchBar.active ? <Header searchBar rounded> <Item> <Icon name="md-search" /> <Input placeholder="Search" /> <Icon name="md-people" /> </Item> <Button transparent> <Text>Search</Text> </Button> </Header> : null } <Content> <List> { characters.map((character, index) => { return ( <ListItem key={index} onPress={navigate.bind(null, 'CharacterDetails', { character })}> <Body> <Text>{character.name}</Text> <Text note>{character.note}</Text> </Body> <Right> <Icon name="md-arrow-round-forward" /> </Right> </ListItem> ); }) } </List> </Content> <Fab active={false} direction="top" containerStyle={{ marginLeft: 10 }} style={{ backgroundColor: '#5067FF' }} position="bottomRight" onPress={this.navigateToAddCharacter}> <Icon name="md-add" /> </Fab> </Container> ); } } export default CharactersScreen;
Here is the view where I delete the object
import React, { Component } from 'react'; import { Alert } from 'react-native'; import { Body, Button, Card, CardItem, Container, Content, Icon, Left, Right, Text } from 'native-base'; import realm from '../realm'; class CharacterDetailsScreen extends Component { static navigationOptions = { title: 'Character: Details' } promptDelete = () => { Alert.alert( 'Delete Character', 'Deleting is irreversible, are you sure?', [ { text: 'Cancel', onPress: () => false }, { text: 'OK', onPress: () => this.deleteCharacter() } ], { cancelable: false } ); } deleteCharacter = () => { let { state: { params: { character } } } = this.props.navigation; let { goBack } = this.props.navigation; realm.write(() => { realm.delete(character); }); goBack(); } render () { let { navigate, state: { params: { character } } } = this.props.navigation; return ( <Container> <Content> <Card> <CardItem header> <Left> <Icon name={character.favorite ? 'md-star' : 'md-person'}/> <Body> <Text>{character.name}</Text> <Text note>{character.note}</Text> </Body> </Left> </CardItem> <CardItem> <Body> <Text>{character.description}</Text> </Body> </CardItem> <CardItem> <Body> <Text>Status</Text> <Text note>{character.status}</Text> </Body> </CardItem> <CardItem> <Left> <Button onPress={this.promptDelete} transparent> <Icon name="md-close" style={{ color: '#FF0000' }} /> <Text style={{ color: '#FF0000' }}> Delete</Text> </Button> </Left> <Right> <Button transparent> <Icon name="md-create" /> <Text> Edit</Text> </Button> </Right> </CardItem> </Card> </Content> </Container> ); } } export default CharacterDetailsScreen;
Solution:
Inside the constructor add one realm listener: So that, soon after change in DB, Screen Data should get refresh. Your action should contain one realm listener to monitor changes in db. Something like this:
realm.addListener('change', () => { this.loadData(); });
export function convertToArray(realmObjectsArray)
{
let copyOfJsonArray = Array.from(realmObjectsArray);
let jsonArray = JSON.parse(JSON.stringify(copyOfJsonArray));
return jsonArray;
}
I have used the same it is working fine but having performance issue for large data in db. Below is the code that working for me with better performance.
export async function getData(schema, filterVariables){
return await Realm.open(databaseOption).then( async realm => {
try {
let data = [];
if(filterVariables){
data = realm.objects(schema).filtered(filterVariables);
data = cloneDeep(_.toArray(data));
}else{
data = realm.objects(schema);
data = cloneDeep(_.toArray(data));
}
realm.close();
return {success: true, data: data};
}
catch (e) {
realm.close();
return {success: false};
}
})
};
@vance-liu 你好,convert each RealmObject to PlainObject 如何实现?可以贴一下代码吗?被这个问题困扰好久了~
Object.assign({}, realmObject);
We're almost celebrating this bug it's first birthday, and from the number of people involved here, it seems like it cost a lot of us hours of investigation, with no elegant solution. Is there any chance this one will be solved? 10x!!!
It has two years old in 2020.
I had this problem today - deleting an object from the underlying realm store will break any flatlist relying on a list of its results.
The majority of solutions in this discussion are the wrong way of working with realm. The entire point of using a no-copy mobile database is exactly that - not to copy - converting & deconverting objects is adding extra overhead that will get worse as n gets higher.
For my specific problem i was able to skirt the issue, FlatLists can use an ExtraData prop to know when to rerender themselves. In your delete action, you must trigger the change of this extra data flag before you actually delete. Additionally you must set up your component to query realm directly when it starts up.
This is the best way to handle it for my particular problem and seems to be working well.
I also believe the listener solution would be another way to fix this.
@techromantic Thanks for the nice post. I haven't tried the extra data option to solve this issue. And It also sounds a bit complex than using listeners to solve the problem from your description. I used the listener to solve this issue and it works out great.
@techromantic your post frames the problem precisely: realm is a zero copy system... an object should be properly ref-counted when used so that it's always valid. the "correct" solution would be to a) fix realm or b) ref count the object yourself... so that deletions are "lazy" and only proceed when all refs are freed up.
@alazier / @tgoyne / @kneth / @appden - Any Updates on this one ?
Even though the
.isValid
method is present in both collection and object, neither of them is doing anything to prevent this error.I tried using Collection.isValid, Object.isValid, Results.snapshot .. nothing works
I'm rendering the Results on one view and if I delete one Object in another view and then return it throws this error.
here is my code for the 2 views
Here is the view where I delete the object