I can't make a list with realm in order to use it with a realm ListView.
I need to make 2 or 3 ListViews, you can see the pieces of code below:
realm.js:
const Realm = require ('realm');
class UserEntrySchema extends Realm.Object {}
UserEntrySchema.schema = {
name:'User',
primaryKey:'id',
properties:{
id:'int',
name:'string',
username: 'string',
email: 'string',
}
};
class UserListSchema extends Realm.Object {}
UserListSchema.schema = {
name:'UserList',
properties: {
users :{type:'list', objectType:'User'}
}
};
class HistorySchema extends Realm.Object {}
HistorySchema.schema = {
name : 'History',
properties :{
items : {type:'list',objectType:'User'}
}
};
export default new Realm({
schema:[UserEntrySchema,UserListSchema,HistorySchema], schemaVersion:0});
I make a first ListView with the following code:
export default class SearchTabScreen1 extends Component {
constructor(props) {
super(props);
this.state = {
searchText:'',
data:[]
};
}
componentDidMount(){
this.fetchUsers();
}
fetchUsers(){
console.log("FEEEEEETCH");
fetch('http://jsonplaceholder.typicode.com/users')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
data : responseJson
});
var data = this.state.data;
realm.write(() => {
for (var i = 0; i < data.length; i++){
let myUser = realm.create('User',data[i],true);
}
console.log("ALLUSER", realm.objects('User'));
});
})
.catch(function(e) { // Failure callback registartion
alert('Failure fetching data');
console.log(e)
});
}
I tried to make a list property using
UserListSchema
with no success.
And for now this ListView works fine even when I'm using
realm.objects('User')
as datasource.
I don't know if it's good to do it like that or not.
The second ListView is a "search history", when a row of the first ListView is clicked, it called the following method that pushes another screen (I am using react-native-navigation package) and populate a realm list. I would like to use this list as datasource for the 'history ListView".
onPushPress(rowData) {
this.props.navigator.showModal({
title: "Random Title",
screen: "Project.WordDefinition",
passProps: {
definition: rowData.name
}
});
realm.write(() => {
let historyList = realm.create('History',{},true);
historyList.items.push({rowData});
});
}
}
I got this error:
'Property' must be of type number
I also tried:
onPushPress(rowData) {
console.log("ROWDATA", rowData);
this.props.navigator.showModal({
title: "Titre",
screen: "AccessiDico.WordDefinition",
passProps: {
definition: rowData.name
}
});
realm.write(() => {
let historyList = realm.create('History',{},true);
historyList.items.push({
id:rowData.id,
name:rowData.name,
username: rowData.username,
email: rowData.email,
});
console.log("ROWDATA",rowData);
console.log("ITEMS",realm.objects('History'));
console.log("List",historyList.items);
});
}
}
And I got this error:
Attempting to create an object of type 'User' with an existing primary
key value
Does it means I can't use "my users" in the 'UserEntrySchema' to push them within a realm list ?
I would really appreciate some help, it has been a week that I am hard stuck with this :+1:
Thanks !
PS: Here how the history ListView is coded:
export default class HistoryTabScreen2 extends Component {
constructor(props) {
super(props);
// if you want to listen on navigator events, set this up
//this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
postDataSource: ds.cloneWithRows(realm.objects('History')),
};
}
renderRow(rowData, sectionId, rowId, highlightRow){
return(
<TouchableHighlight onPress={this.onPushPress.bind(this)}>
<View style={styles.row}>
<Text style={styles.rowText}>{rowData.name}</Text>
</View>
</TouchableHighlight>
)
}
render(){
return(
<ListView
dataSource={this.state.postDataSource}
renderRow={this.renderRow.bind(this)}
/>
);
}
And the log of my rowData when I clicked a row of the ListView:
'ROWDATA', { id: 5,
name: 'Chelsey Dietrich',
username: 'Kamren',
email: 'Lucio_Hettinger#annie.ca',
address:
{ street: 'Skiles Walks',
suite: 'Suite 351',
city: 'Roscoeview',
zipcode: '33263',
geo: { lat: '-31.8129', lng: '62.5342' } },
phone: '(254)954-1289',
website: 'demarco.info',
company:
{ name: 'Keebler LLC',
catchPhrase: 'User-centric fault-tolerant solution',
bs: 'revolutionize end-to-end systems' } }
I just responded to a question about list objects.
take a look at this link, and then ask for further clarification if you need it. At the end of the post I provided a working example of creating/modifying/appending/deleting objects from a realm List object.
How can I properly copy objects from one Realm object to another object
To create a list is pretty straightforward, here's the simplest case:
class Letters: Object {
var letterList = List<Letter>()
}
So to create a list, you need to know the Object subclass you will be using. (Letter in the above example).
To add to the list, you create an object (item - below), and then append to the list:
firstList.letterList.append(item)
Related
I am building an integrated app with Android native and React native communicating with each other.
For sending data from Native to React native I tried to pass data by using initial props but it was not working and showing undefined. Then I tried to use DeviceEventEmitter which kind of worked but there was a slight problem.
EDITED :
Here's the code snippet:
class Details extends Component {
constructor(props){
super(props);
this.state={data: '', id: '278'}
}
componentDidMount(){
const eventEmitter = new NativeEventEmitter();
this.subscription = eventEmitter.addListener('customEventName',(e: Event)=>{
this.setState({id: e.key1});
console.warn(this.state.id);
});
const API_key = "APIkey"
console.warn(this.state.id);
const URL = "https://api.themoviedb.org/3/movie/" + this.state.id + "?api_key=" + API_key + "&language=en-USs"
return fetch(URL, {
method: 'GET'
})
.then((response) => response.json())
.then((responseJson) => {
this.setState({
data: responseJson,
},
function(){
});
})
.catch((error) =>{
console.error(error);
});
}
componentWillUnmount(){
this.subscription.remove();
}
render() {
return(
/*something*/
);
}
}
The value of id is being successfully sent from native component to React native component.
Problem: The console.warn() inside addlistener() is showing after the console.warn() which is below declaring the API_key, and hence the this.state.id is not being updated.
Please any help will be appreciated.
your event register should be something as mentioned below, as you are registering the event so the scope of this should be event handler specific so if you want to access the parent scope you need to use the arrow function like mentioned below.
DeviceEventEmitter.addListener('customEventName',(e: Event)=> {
this.id = e.key1
console.warn("inside event emitter", this.id);
});
If you are successfully getting the event then I think this is just a React problem.
It looks like you want to fetch after you have successfully got the ID, but you're trying to fetch straight away in componentDidMount.
As fetch is a side effect you probably want to use componentDidUpdate like so:
import { NativeEventEmitter } from 'react-native'
constructor(props){
super(props);
this.state={
data: '',
id: ''
}
}
componentDidMount(){
const eventEmitter = new NativeEventEmitter();
this.subscription = eventEmitter.addListener('customEventName',(e: Event)=>{
this.setState({id: e.key1});
console.warn(this.state.id);
});
}
componentDidUpdate() {
const { id } = this.state
if (id) {
const URL = "https://api.themoviedb.org/3/movie/" + this.state.id + "?api_key=" + API_key + "&language=en-USs"
return fetch(URL, {
method: 'GET'
})
// ... etc
}
}
// ...etc
Note that id starts out as empty.
I'm trying to read data from a realtim database in firebase but I can not get this information to be rendered in a Text component. I can only show the information of the object by console.log and decompose it but in the render of the screen the information is not shown.
class UserProfileScreen extends Component<Props> {
state = {
dataUser : []
}
componentDidMount(){
const { uid } = firebaseAuth.currentUser
this.getUserRef().child(uid).once('value',function(snapshot){
dataUser = snapshot.val()
console.log(dataUser.username)
})
}
getUserRef = () => {
return firebaseDatabase.ref('users')
}
render(){
const {dataUser} = this.state
return(
<View style={styles.container}>
<Text>{dataUser.username}</Text>
</View>
)
}
}
Object obtained from the database displayed by console:
,
Android Emulator:
What I can be doing wrong ?
You need to change the state property once the value has been retrieved:
constructor() {
this.state = { dataUser: {} };
}
componentDidMount(){
...
this.getUserRef().child(uid).once('value',function(snapshot){
dataUser = snapshot.val()
this.setState({
dataUser: dataUser // es5
dataUser // es6
});
});
...
}
Documentation
I'm dynamically creating components in create-react-native-app. Everything is working fine using the expo app for testing in Development mode using npm start, and connecting with an android phone.
If I switch it to Production mode, or try to build the apk as a Standalone app the object is not created on the Button press.
This is my first project with React Native, and I don't know how to debug this.
I've also been unable to find any information about what the differences between these two modes might be that would lead to this.
Here the relevant code:
export default class App extends React.Component {
constructor(props) {
super(props);
this.updateState = this.updateState.bind(this);
this.state = {
knobs: [],
key: 1
}
}
add = () => {
let key = this.state.key + 1
let knob = (<Object key={key} updateState={this.updateState}/>);
let knobs = this.state.knobs;
knobs.push(knob);
this.setState({knobs: knobs, key: key})
}
render = () => {
return ([<View>
{this.state.knobs}
<Button onPress={() => this.add()} title='add thing'/>
</View>
]);
}
}
I'm not sure what causes the issue since we don't have any sort of error message but below snippet of code might help.
When you assign a variable like below;
let knobs = this.state.knobs;
You are not creating a new variable, you are creating a reference to the original property. Because of this you mutate the state. This might cause the issue.
For setting new state values related to current state values you can use functional setState syntax and destructuring assignment. It is a little bit more easy to use and a little bit more easy to read.
add = () => {
this.setState((prevState) => {
const { knobs, key } = prevState; // deconstruct array and key from state
const newKnob = (<Object key={(key + 1)} updateState={this.updateState}/>);
knobs.push(newKnob); // push new item to array
return { knobs, key: (key + 1) } //return new state values
});
}
Oh, so in the end I rewrote the whole bit.
Moving the objects to be created into the render function.
export default class App extends React.Component {
constructor() {
super();
this.state = {
things: []
}
this.key = 0;
}
add = () => {
let addThing = { key: this.key }
this.setState({ things: [ ...this.state.things, addThing ] })
this.key = this.key + 1;
}
render() {
let newThings = this.state.things.map((key) => {
return (
<Text key={key}>New Thing.</Text>
);
});
return (<View style={styles.container}>
{newThings}
<Button onPress={() => this.add()} title='add thing'/>
</View>);
}
}
This functions as expected in Production mode and as an App;)
guys! I first making app with and have some problem with response values! When i click GO, i sent request and get response from it. Im looking in the console, i have 20 items from response on 'london' locate, so it works, but doesnt parse my json to key-valuse! Help me, please, guys!
Using latest React-native + android virtual emulator 7.1.1
Here is my code from SearchPage.js
function urlForQueryAndPage(key, value, pageNumber) {
var data = {
country: 'uk',
pretty: '1',
encoding: 'json',
listing_type: 'buy',
action: 'search_listings',
page: pageNumber
};
data[key] = value;
var querystring = Object.keys(data)
.map(key => key + '=' + encodeURIComponent(data[key]))
.join('&');
return 'http://api.nestoria.co.uk/api?' + querystring;
};
export default class SearchPage extends Component {
constructor(props) {
super(props);
this.state = {
searchString: 'london',
isLoading: false,
message: ''
};
}
onSearchTextChanged(event) {
this.setState({ searchString: event.nativeEvent.text });
}
onSearchPressed() {
var query = urlForQueryAndPage('place_name', this.state.searchString, 1);
this._executeQuery(query);
}
_executeQuery(query) {
this.setState({ isLoading: true });
console.log(query);
fetch(query)
.then(response => response.json())
.then(json => this._handleResponse(json.response))
.catch(error =>
this.setState({
isLoading: false,
message: 'Something bad happened ' + error
}));
}
_handleResponse(response) {
this.setState({ isLoading: false , message: '' });
if (response.application_response_code.substr(0, 1) === '1') {
console.log('Properties found: ' + response.listings.length);
this.props.navigator.push({
id: 'SearchResults',
name: 'SearchResults',
passProps: {listings: response.listings}
});
console.log(passProps);
} else {
this.setState({ message: 'Location not recognized; please try again.'});
}
}
And here is my code from SearchResults.js
export default class SearchResults extends Component {
constructor(props) {
super(props);
var dataSource = new ListView.DataSource(
{rowHasChanged: (r1, r2) => r1.lister_url !== r2.lister_url});
this.state = {
dataSource: dataSource.cloneWithRows(this.props.listings)
};
}
renderRow(rowData, sectionID, rowID) {
return (
<TouchableHighlight
underlayColor='#dddddd'>
<View>
<Text>{rowData.title}</Text>
</View>
</TouchableHighlight>
);
}
render() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow.bind(this)}/>
);
}
}
Look at the error text ( in red pointer)
End here it is response from console. Look at the items count!So response works!
Two things:
1-Try to put the .then right after response.json() like so:
fetch(query)
.then((response) => {
response.json()
.then(json => this._handleResponse(json.response))})
.catch(error =>
Update: Actually, changing the order of the .then is not necessary, it should work either way.
2-I believe that when you console.log(passProps), passProps is not defined properly, therefore, console.log(passProps) won't print anything (Correct me if I am wrong). You can try this:
var passProps = {listings: response.listings};
this.props.navigator.push({
id: 'SearchResults',
name: 'SearchResults',
passProps: passProps
});
console.log(passProps);
I see that you are using this.props.listings inside your SearchResults component after passing listings as props using the navigator. The only way for you to be able to do this.props.listings directly (instead of this.props.passProps.listings) is if you have something like this in your renderScene method of your navigator:
if (routeId === 'SearchResults') {
return (<SearchResults {...route.passProps} navigator={navigator} />);
}
or
if (route.id === 'SearchResults') {
return (<SearchResults listings={route.passProps.listings} navigator={navigator} />);
}
To make sure you are passing the props correctly to the SearchResults component, do a console.log in your render method of SearchResults
render() {
console.log("SearchResults props: ", this.props);
return (
<ListView
I believe that if you get the fetch output right (as an object), the problem could be the way you wrote your ListView and/or dataSource.
Other than that, there is not enough information (Such as the expected json response, and what you actually got) to tell where the problem lies.
Cheers
I am using SQLite as the device's database. What I am trying to basically achieve is this:
1- Give a user the ability to star his favorite "data"
2- Once the data gets saved in the db, retrieve it inside another page and insert them into a listView for the user to see at any time.
But no matter how much I try, I am always getting the same error.
Cannot read property of undefined.
The code:
import React, { Component } from 'react'
import {
View,
Text,
ListView
} from 'react-native'
var SQLite = require('react-native-sqlite-storage')
var db = SQLite.openDatabase({ name: "RHPC.db", location: "default"})
var obj;
class Schedules extends Component {
constructor(props) {
super(props)
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
});
this.state = {
datasource: []
}
db.transaction((tx) => {
tx.executeSql("SELECT * FROM schedules", [], (tx, res) => {
let len = res.rows.length;
if(len > 0) {
for(let i = 0; i < len; i++) {
var obj = [{id: res.rows.item(i)["id"], title: res.rows.item(i)["title"]}]
}
this.setState({
datasource: obj
})
} else {
console.log("empty")
}
})
}, (err) => {
console.log("error: " + JSON.stringify(err))
})
}
_renderRow(rowData) {
return(
<View>
<Text key={rowData.id}>
{rowData.title}
</Text>
</View>
)
}
render() {
console.log(this.state.datasource);
return(
<View style={{marginTop: 150}}>
<ListView
dataSource={this.state.datasource}
renderRow={this._renderRow.bind(this)}
/>
</View>
);
}
}
const styles = {
}
export default Schedules;
When I try to console.log the dataSource state:
0: Object
id: 2
title: "Session 1: Transition from Humanitarian Assistance to Rebuilding Health & Health Systems."
So in other words it looks like it's working but not 100%? Because I do have two rows inside that table and it's only retrieving the last one. Is this the cause of the undefined issue?
You use ListView in a wrong way, you create new dataSource in constructor (ds) and not assign it anywhere, checkout example in documentation: https://facebook.github.io/react-native/docs/listview.html
It should be:
constructor(props) {
super(props)
this.state = {
dataSource: new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}),
}
}
And in setState make something like this:
this.setState({
datasource: this.state.dataSource.cloneWithRows(obj)
})
Edit:
And in your for loop you should have:
var obj = [];
for(let i = 0; i < len; i++) {
obj.push({id: res.rows.item(i)["id"], title: res.rows.item(i)["title"]});
}