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
Related
I need bluetooth data of surrounding ibeacons. (device name, mac address, rssi value) I can get these values. But major and minor values are important to me. how can i get them? I use react-native-ble-plx library. What solutions can you suggest me?
Library's Documentation: https://dotintent.github.io/react-native-ble-plx/
My Codes:
import React, { useState } from 'react';
import {
Button,
SafeAreaView,
ScrollView,
StatusBar,
StyleSheet,
Text,
useColorScheme,
View,
} from 'react-native';
import {
Colors,
DebugInstructions,
Header,
LearnMoreLinks,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';
import {BleManager} from 'react-native-ble-plx';
import useBLE from './useBLE';
var Buffer = require('buffer/').Buffer;
import base64 from 'react-native-base64';
const Parser = require("binary-parser").Parser;
const App = () => {
const manager = new BleManager();
const {requestPermissions} = useBLE();
useState(() => {
requestPermissions((isGranted) => {
if (!isgranted) {
alert("android permission granted: " + isGranted);
}
});
}, []);
// const ibeacon_format = Struct(
// "uuid" / Array(16, Byte),
// "major" / Int16ub,
// "minor" / Int16ub,
// "power" / Int8sl,
// )
const ibeaconFormat = new Parser()
.int16("major")
.int16("minor");
function deneme() {
manager.startDeviceScan(null, null, (error, device) => {
console.log("device id: ",device.id);
console.log("device name: ", device.localName);
console.log("device rssi: ", device.rssi);
// console.log(device.readCharacteristicForService());
console.log("--------------------");
// let data = new Buffer(device.manufacturerData.toString("base64"));
// console.log(data);
// let data = device.manufacturerData[0x004C];
// let beacon = ibeacon_format.parse(data);
// console.log(beacon);
// let data = Buffer.from(device.manufacturerData, "base64");
// console.log(ibeaconFormat.parse(data));
if (error) {
console.log(error);
}
});
}
function durdur() {
manager.stopDeviceScan();
}
return (
<View>
<Text>Hello World</Text>
<Button title="Deneme" onPress={deneme} />
<Button title="Durdur" onPress={durdur} />
</View>
);
};
export default App;
// let time = date.getTime();
// let seconds = parseInt(time / 1000);
// let data = new Buffer(4);
// data.writeUInt32BE(seconds);
// this.manager.writeCharacteristicWithResponseForDevice(deviceId, serviceUUID, charUUID, data.toString('base64'))
// .then((success) => {
// resolve(success);
// })
// .catch((error) => {
// reject(error)
// })
// });
I'm still learning to use React Native and runnig into an issue with the stack size being exceeded but I'm unsure why. Looking at other posts I see it must be that the screen is being rerendered too many times and is stuck in a loop but how can I prevent this happening?
RaceListScreen
export function RandomRaceScreen(this: any, {navigation: navigation}) {
const [raceList, setRaceList] = useState<RaceModel[]>([]);
useEffect(() => {
const fetchedRaces: RaceModel[] = getCoreRaceList();
setRaceList(fetchedRaces);
}, []);
//number of players must be less than max number of available races
const racePressed = (raceId: number) => {
console.log('Displaying info about Race, ', raceId);
navigation.navigate('RaceLoreListScreen', {raceId: raceId});
};
const renderRaces = (item: unknown) => {
return (
<RaceCard
race={item.item}
onClick={() => {
racePressed(item.item._groupId);
}}
/>
);
};
const width = Dimensions.get('window').width;
return (
<ImageBackground
source={require('../../assets/space_background_reduced_v1.png')}
style={globalStyles.background}>
<FlatList
data={raceList}
renderItem={renderRaces}
sliderWidth={width}
containerCustomStyle={style.carousel}
contentContainerCustomStyle={style.card}
itemWidth={width * 0.8}
layout="default"
removeClippedSubviews={false}
/>
</ImageBackground>
);
}
getCoreRaceList function:
import {RaceModel} from '../../models/RaceModel';
import races from '../../races/core_races.json';
export function getCoreRaceList(): RaceModel[] {
let raceList: RaceModel[] = [];
for (let i = 0; i < 5; i++) {
raceList.push(
new RaceModel(races[i], races[i].name, races[i].homeworld, false),
);
}
return raceList;
}
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>
);
}
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
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"]});
}