I am trying to fetch from db-models to ListView. Here is my code:
export default class todoDB extends Component {
constructor(props) {
super(props);
this.state = {
dataSource : new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2})
};
}
componentDidMount () {
this.fetchData();
}
fetchData () {
DB.users.get_all(function(result) {
let data = [];
for(let i = 1; i <= result.totalrows; i++) {
data.push(result.rows[i]);
}
this.setState({
dataSource: dataSource.cloneWithRows(data),
})
});
}
render () {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderList}
/>
);
}
renderList (item) {
return (
<View>
<Text>{item.age}</Text>
</View>
);
}};
After running I don`t have error or any output, only empty screen.
I using
"react": "15.4.2",
"react-native": "0.40.0"
"react-native-db-models": "^0.1.3"
I have not tested it but you could try this :
fetchData() {
DB.users.get_all((result) => {
let data = [];
for (let i = 1; i <= result.totalrows; i++) {
data.push(result.rows[i]);
}
this.setState((prevState) => (
{
dataSource: prevState.dataSource.cloneWithRows(data)
}));
});
}
Changes are : using arrow function instead of function(result) to keep the scope of this and updating the previous state prevState.dataSource.cloneWithRows(data) (in your code dataSource was undefined here)
As to why use prevState, it is to keep immutability. Little bit more info here : https://facebook.github.io/react/docs/react-component.html#setstate
Related
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
Hi, Thanks in advance, am using the Double click Component and it
works well for double click event. But I need to get an action when
user perform a single click. What the work around for this issue.
<DoubleClick onClick={(e) => this.hClick(value,e)}>
<View>
<Text>
{value.item}
</Text>
</View>
</DoubleClick>
I wrote a component.
// #flow
import * as React from 'react';
import { TouchableOpacity } from 'react-native';
import type { PressEvent } from 'react-native/Libraries/Types/CoreEventTypes';
type Props = {
children?: any,
onSingleTap: (event: PressEvent) => void,
onDoubleTap: (event: PressEvent) => void,
};
const MAX_DOUBLE_TOUCH_DISTANCE = 20;
const MAX_DOUBLE_TOUCH_DELAY_TIME = 250;
class SingleDoubleTap extends React.Component<Props> {
_timer: TimeoutID;
_previousPressEvent: ?PressEvent;
onPress = (event: PressEvent) => {
if (this._previousPressEvent) {
this.onReceiveSecondEvent(event);
} else {
this.onReceiveFirstEvent(event);
}
};
onReceiveFirstEvent = (event: PressEvent) => {
this._timer = setTimeout(() => {
this.props.onSingleTap(event);
this._previousPressEvent = null;
}, MAX_DOUBLE_TOUCH_DELAY_TIME);
this._previousPressEvent = event;
};
onReceiveSecondEvent = (event: PressEvent) => {
if (this._isDoubleTap(event)) {
this.props.onDoubleTap(event);
} else {
this.props.onSingleTap(event);
}
this._timer && clearTimeout(this._timer);
this._previousPressEvent = null;
};
_distanceBetweenTouches = (
touch1: PressEvent,
touch2: PressEvent
): number => {
const disX = touch1.nativeEvent.locationX - touch2.nativeEvent.locationX;
const disY = touch1.nativeEvent.locationY - touch2.nativeEvent.locationY;
return Math.sqrt(Math.pow(disX, 2) + Math.pow(disY, 2));
};
_isDoubleTap = (currentEvent: PressEvent) => {
if (!this._previousPressEvent) {
return false;
}
const distance = this._distanceBetweenTouches(
currentEvent,
this._previousPressEvent
);
// $FlowFixMe
const { nativeEvent } = this._previousPressEvent;
const delay = currentEvent.nativeEvent.timestamp - nativeEvent.timestamp;
return (
distance < MAX_DOUBLE_TOUCH_DISTANCE &&
delay < MAX_DOUBLE_TOUCH_DELAY_TIME
);
};
componentWillUnmount = () => {
this._timer && clearTimeout(this._timer);
};
render() {
return (
<TouchableOpacity onPress={this.onPress}>
{this.props.children}
</TouchableOpacity>
);
}
}
export default SingleDoubleTap;
How to use it?
<SingleDoubleTap
onSingleTap={this._onSingleTap}
onDoubleTap={this._onDoubleTap}>
..... // other components
</SingleDoubleTap>
The key thing is you should wait for the DoubleTap event failed to recognize the touch event as OneTap.
Remove the double click and use touchable component. pass the click to function and find whether its single or double click using timer delay
I'm having serious issues with the RN Picker Item, whenever I try to load the picker Items I get the following error.
undefined is not an object (evaluating 'this.inputProps.value')
Here us the screenshot.
This is my code - Component - Basic
import React, { Component } from 'react';
import { Picker } from 'react-native';
export default class Basic extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
var options = this.props.list.map((item, key) => {
return <Picker.Item label={item} value={item} key={key} /> ;
});
return (
<Picker mode="dropdown" selectedValue={this.props.selected} supportedOrientations={['portrait','landscape']} {...this.props}>
{ this.props.default && <Picker label={this.props.default} value=""/> }
{ options }
</Picker>
);
}
}
File - Dynamic OptionSet
This will use the Basic component to display the Picker.
class DynamicOptionSets extends Component {
constructor(props) {
super(props);
this.state = {};
this.ucfirst = this.ucfirst.bind(this);
this._renderMain = this._renderMain.bind(this);
this._renderSpinner = this._renderSpinner.bind(this);
}
componentWillMount() {
InteractionManager.runAfterInteractions(() => {
this.props["get"+this.ucfirst(this.props.option)]();
});
}
ucfirst(string)
{
return string.charAt(0).toUpperCase() + string.slice(1);
}
render() {
return (
<View>
{this._renderSpinner()}
{this._renderMain()}
</View>
);
}
_renderMain(){
if(!this.props[this.props.option]['data']){
return null;
}
return (
<Basic list={this.props[this.props.option]['data']} { ...this.props }/>
)
}
_renderSpinner(){...}
}
const mapDispatchToProps = (dispatch, ownProps) => {
var {getCountries, getStates,
getDepartments, getBranches,
getBusinessSectors, getGenPostingGroup,
getCustPostingGroup, getVatPostingGroup,
getPricelist, getSalesPersons
} = ActionCreators;
return bindActionCreators({
getCountries, getStates,
getDepartments, getBranches,
getBusinessSectors, getGenPostingGroup,
getCustPostingGroup, getVatPostingGroup,
getPricelist, getSalesPersons
}, dispatch);
}
const mapStateToProps = (state) => {
var {
countries, countriesUpdate,
states, statesUpdate,
departments, departmentsUpdate,
branches, branchesUpdate,
businessSectors, businessSectorsUpdate,
genPostingGroup, genPostingGroupUpdate,
ccustPostingGroup, ccustPostingGroupUpdate,
vatPostingGroup, vatPostingGroupUpdate,
pricelist, pricelistUpdate,
salesPersons, salesPersonsUpdate,
} = state;
return {
countries, countriesUpdate,
states, statesUpdate,
departments, departmentsUpdate,
branches, branchesUpdate,
businessSectors, businessSectorsUpdate,
genPostingGroup, genPostingGroupUpdate,
ccustPostingGroup, ccustPostingGroupUpdate,
vatPostingGroup, vatPostingGroupUpdate,
pricelist, pricelistUpdate,
salesPersons, salesPersonsUpdate,
}
}
export default connect(mapStateToProps, mapDispatchToProps)(DynamicOptionSets);
So now I can call the dynamic option set like a regular picker component only and specify the data group (option)
<DynamicOptionSets option="salesPersons" mode="dropdown" onValueChange={this._updateValue.bind(this, 'salesperson')} selectedValue={this.state.form_data.salesperson} />
I don't understand why this is happening as this is the exact way I render Pickers dynamically in RN. I have gone through the doc and followed the instructions as specified.
NB: I'm dynamically loading the picker so it's inside a component I'm calling whenever I need to, display a picker that should explain the {... this.props} on the picker component.
You have a basic mistake in your code.
render() {
var options = this.props.list.map((item, key) => {
return <Picker.Item label={item} value={item} key={key} /> ;
});
return (
<Picker mode="dropdown" selected={this.props.selected} supportedOrientations={['portrait','landscape']}>
{/*_________________^^^^^^^^____ You should place `selectedValue` here instead */}
{ this.props.default && <Picker.Item label={this.props.default} value=""/> }
{ options }
</Picker>
);
}
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"]});
}