I am trying to implement a swipe card .Could someone help me with this error
import React, { Component } from 'react';
import { Text, Animated, Dimensions, PanResponder } from 'react-native';
class AlbumDetail extends Component {
constructor(props) {
super(props);
console.log('print log 1');
const position = new Animated.valueXY();
console.log('print log 2');
const panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove: (event, gesture) => {
position.setValue({ x: gesture.dx, y: gesture.dy });
},
onPanResponderRelease: (event, gesture) => {
if (gesture.dx > SWIPE_THRESHOLD) {
forcedSwipe('right');
} else if (gesture.dx < -SWIPE_THRESHOLD) {
forcedSwipe('left');
} else {
this.resetPosition();
}
}
});
this.state = { panResponder, position};
}
render() {
return (
<Animated.View
style={this.position.getLayout()}
{...this.state.panResponder.panHandlers}
>
{this.renderCard}
</Animated.View>
)}
}
the log error shows this
print log 1
Possible Unhandled Promise Rejection (id: 0): TypeError: undefined is
not a constructor (evaluating 'new _reactNative.Animated.valueXY()')
You made mistake in this line:
new Animated.ValueXY() //capital V
Please refer documentation for further details
Related
I'm having issues with accessing this.state and this.setState inside the onCancel/onOk function. I want to modify the state after confirmation or canceling the pop-up modal. If anyone's got a different approach, your guidance would be helpful.
import React from 'react';
import { Button, Modal } from 'antd';
class ExampleClass extends React.Component {
constructor() {
super();
this.state = {
bankInfo: 100,
};
}
onButtonClicked() {
this.setState({ bankInfo: 200 }); // works fine
Modal.confirm({
title: 'Are you sure delete this item?',
okType: 'danger',
onOk() {
this.setState({ bankInfo: 300 }); // Uncaught TypeError: Cannot read property 'setState' of undefined
},
onCancel() {
this.setState({ bankInfo: 400 }); // Uncaught TypeError: Cannot read property 'setState' of undefined
},
});
}
render() {
return (
<div>
<Button onClick={this.onButtonClicked.bind(this)}>Click Me</Button>
</div>
);
}
}
export default ExampleClass;
I would prefer to use arrow function
import React from 'react';
import { Button, Modal } from 'antd';
class ExampleClass extends React.Component {
constructor() {
super();
this.state = {
bankInfo: 100,
};
}
onButtonClicked = () => {
this.setState({ bankInfo: 200 });
Modal.confirm({
title: 'Are you sure delete this item?',
okType: 'danger',
onOk: () => {
this.setState({ bankInfo: 300 });
},
onCancel: () => {
this.setState({ bankInfo: 400 });
},
});
}
render() {
return (
<div>
<Button onClick={this.onButtonClicked}>Click Me</Button>
</div>
);
}
}
export default ExampleClass;
You need to bind your method to the class.
import React from 'react';
import { Button, Modal } from 'antd';
class ExampleClass extends React.Component {
constructor() {
super();
this.state = {
bankInfo: 100,
};
}
onOkHandler = () => {this.setState({ bankInfo: 300 })}
onCancelHandler = () => {this.setState({ bankInfo: 400 })}
onButtonClicked() {
this.setState({ bankInfo: 200 }); // works fine
Modal.confirm({
title: 'Are you sure delete this item?',
okType: 'danger',
onOk() {
this.onOkHandler()
},
onCancel() {
this.onCancelHandler()
},
});
}
render() {
return (
<div>
<Button onClick={this.onButtonClicked.bind(this)}>Click Me</Button>
</div>
);
}
}
export default ExampleClass;
I created the below HOC which I can use to wrap a React component to add 2 inactivity timers: the first to show the user a warning; the other to log them out. I got the idea from here and it seems to work pretty well. That is, I can add withTimer functionality to a component by wrapping it like this:
export default withTimer(DragDropContext(HTML5Backend)(App));
The problem is the warning alert box halts the event loop (as alert boxes apparently always do), so the logout function is never reached.
I believe a modal (e.g., from react-bootstrap) would solve this, as it presumably would not halt the event loop, thus the logout would occur as intended if the user is still idle after the warning alert.
How would I change the below HOC to use a modal for the warning instead of an alert box? Is this possible? That is, can a HOC that's used to wrap another component include a component itself (i.e., the modal) so as to keep it decoupled from the wrapped component itself?
import React from 'react';
import { Modal } from 'react-bootstrap';
const withTimer = (WrappedComponent) => {
class WithTimer extends React.Component {
constructor(props) {
super(props);
this.state = {
warningTime: 5000,
signoutTime: 10000
};
this.events = [
'load',
'mousemove',
'mousedown',
'click',
'scroll',
'keypress'
];
for (var i in this.events) {
window.addEventListener(this.events[i], this.resetTimeout);
}
this.setTimeout();
}
clearTimeoutFunc = () => {
if (this.warnTimeout) clearTimeout(this.warnTimeout);
if (this.logoutTimeout) clearTimeout(this.logoutTimeout);
};
setTimeout = () => {
this.warnTimeout = setTimeout(this.warn, this.state.warningTime);
this.logoutTimeout = setTimeout(this.logout, this.state.signoutTime);
};
resetTimeout = () => {
this.clearTimeoutFunc();
this.setTimeout();
};
warn = () => {
window.alert('You will be logged out soon. Click to stay logged in.');
};
logout = () => {
window.alert('You are being logged out!');
// log the user out here
};
render() {
console.log('HOC');
return <WrappedComponent {...this.props.children} />;
}
}
return WithTimer;
};
export default withTimer;
If you wanted to use a Modal, you could do something like this:
Live Demo
withTimer.js
import React from 'react';
import MyModal from './MyModal';
const withTimer = (WrappedComponent) => {
class WithTimer extends React.Component {
constructor(props) {
super(props);
this.state = {
warningTime: 5000,
signoutTime: 10000,
showModal: false,
modalMessage: "",
modalButtonText: "",
};
this.events = [
'load',
'mousemove',
'mousedown',
'click',
'scroll',
'keypress'
];
for (var i in this.events) {
window.addEventListener(this.events[i], this.resetTimeout);
}
this.setTimeout();
}
clearTimeoutFunc = () => {
if (this.warnTimeout) clearTimeout(this.warnTimeout);
if (this.logoutTimeout) clearTimeout(this.logoutTimeout);
};
setTimeout = () => {
this.warnTimeout = setTimeout(this.warn, this.state.warningTime);
this.logoutTimeout = setTimeout(this.logout, this.state.signoutTime);
};
resetTimeout = () => {
this.clearTimeoutFunc();
this.setTimeout();
};
onModalClick = () => {
this.setState({
showModal: false,
}, () => this.resetTimeout())
}
warn = () => {
this.setState({
modalButtonText: "Stay Logged In",
modalHeader: "Warning!",
modalMessage: 'You will be logged out soon. Click to stay logged in.',
showModal: true,
});
};
logout = () => {
this.setState({
modalButtonText: "Ok",
modalHeader: "Session Timed Out",
modalMessage: 'You are being logged out!',
showModal: true,
});
// log the user out here
};
render() {
console.log('HOC');
return (
<>
<MyModal
show={this.state.showModal}
modalMessage={this.state.modalMessage}
modalHeader={this.state.modalHeader}
buttonText={this.state.modalButtonText}
onButtonClick={this.onModalClick} />
<WrappedComponent {...this.props.children} />
</>
);
}
}
return WithTimer;
};
export default withTimer;
MyModal.js
import React, { useState } from "react";
import { Modal, Button } from "react-bootstrap";
function MyModal({ show = false, modalMessage, modalHeader, onButtonClick, buttonText }) {
const handleClick = event => {
onButtonClick(event);
}
return (
<Modal show={show} onHide={handleClick} animation={false}>
<Modal.Header closeButton>
<Modal.Title>{modalHeader}</Modal.Title>
</Modal.Header>
<Modal.Body>{modalMessage}</Modal.Body>
<Modal.Footer>
<Button variant="primary" onClick={handleClick}>
{buttonText}
</Button>
</Modal.Footer>
</Modal>
);
}
export default MyModal;
Yes, you can render any components you'd like in the HOC. So in your case you can render a <Modal/>.
Of course, whether the modal is displayed or not is dynamic, so that's a perfect job for the component's state to come into play. Use conditional statements in your render function to either render or not render your modal.
import React from 'react';
import { Modal } from 'react-bootstrap';
const withTimer = (WrappedComponent) => {
class WithTimer extends React.Component {
constructor(props) {
super(props);
this.state = {
showWarning: false,
showLogout: false,
warningTime: 5000,
signoutTime: 10000
};
this.events = [
'load',
'mousemove',
'mousedown',
'click',
'scroll',
'keypress'
];
for (var i in this.events) {
window.addEventListener(this.events[i], this.resetTimeout);
}
this.setTimeout();
}
clearTimeoutFunc = () => {
if (this.warnTimeout) clearTimeout(this.warnTimeout);
if (this.logoutTimeout) clearTimeout(this.logoutTimeout);
};
setTimeout = () => {
this.warnTimeout = setTimeout(this.warn, this.state.warningTime);
this.logoutTimeout = setTimeout(this.logout, this.state.signoutTime);
};
resetTimeout = () => {
this.clearTimeoutFunc();
this.setTimeout();
};
warn = () => {
this.setState({ showWarning: true });
};
logout = () => {
this.setState({ showLogout: true });
// log the user out here
};
render() {
let modal;
if (this.state.showLogout) {
modal = <Modal>...</Modal>;
} else if (this.state.showWarning) {
modal = <Modal>...</Modal>;
} else {
modal = null;
}
return <React.Fragment>
<WrappedComponent {...this.props.children} />
{ modal }
</React.Fragment>;
}
}
return WithTimer;
};
export default withTimer;
I have the following screen where I call a helper function pouchDB_helper.sync() to gather a bunch of data for me.
The goal is to be able to record where in the function it is currently at so I can give a percent or a status update in my render()
I'm new to react / react-native so I'm not sure if this is the right way to go about doing it. I'd like to be able to keep it as a helper function if possible because I use this function in other areas, this is just the only place I actually need a status update on where it's at in the process.
import React, { Component } from 'react';
import { ActivityIndicator, AsyncStorage, Button, StatusBar, Text, StyleSheet, View, } from 'react-native';
import * as pouchDB_helper from '../utils/pouchdb';
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'flex-start',
justifyContent: 'center',
padding: "5%",
backgroundColor: "#fff",
width:"100%"
},
statusHeader: {
fontSize: 18,
fontWeight: "600",
marginBottom: 10,
textAlign:'center',
width:'100%'
}
});
type Props = {};
export default class SyncScreen extends Component<Props> {
static navigationOptions = {
title: 'Syncing Settings',
};
render() {
pouchDB_helper.sync().then((response) => {
//IT'S DONE
}, (error) => { alert("THERE WAS AN ERROR"); });
return (
<View style={styles.container}>
<Text style={styles.statusHeader}>Syncing, please wait..</Text>
<Text>WHERE I WANT TO CHANGE TEXT</Text>
</View>
);
}
}
pouchDB_helper example
note: This is just an example. I know the .get() won't take long enough to warrant a status but I'm just trying to understand the concept.
import React from 'react';
import { AsyncStorage } from 'react-native';
import PouchDB from 'pouchdb-react-native'
export async function sync() {
const company_id = await AsyncStorage.getItem('company_id');
const device_db = new PouchDB(company_id, {auto_compaction: true});
//STATUS UPDATE 1
return device_db.get("settings").then((s) => {
//STATUS UPDATE 2
return device_db.get("get_this").then((s) => {
//STATUS UPDATE 3
return device_db.get("get_that").then((s) => {
//STATUS UPDATE 4
}, (error) => { return false; });
}, (error) => { return false; });
}, (error) => { return false; });
}
Simple approach would be passing a function to the sync function which can change the state and set the desired text on component.
Example
constructor(props) {
super(props);
this.state = {
level: 'some init value'
};
}
onChangeState = (level) => {
this.setState({level});
}
componentDidMount() {
pouchDB_helper.sync(this.onChangeState).then((response) => {
//IT'S DONE
this.onChangeState('Finished');
}, (error) => { alert("THERE WAS AN ERROR"); });
}
render() {
return (
<View style={styles.container}>
<Text style={styles.statusHeader}>Syncing, please wait..</Text>
<Text>{`Current level is ${this.state.level}`}</Text>
</View>
);
}
export async function sync(changeState) {
const company_id = await AsyncStorage.getItem('company_id');
const device_db = new PouchDB(company_id, {auto_compaction: true});
//STATUS UPDATE 1
changeState(1);
return device_db.get("settings").then((s) => {
//STATUS UPDATE 2
changeState(2);
return device_db.get("get_this").then((s) => {
//STATUS UPDATE 3
changeState(3);
return device_db.get("get_that").then((s) => {
//STATUS UPDATE 4
changeState(4);
}, (error) => { return false; });
}, (error) => { return false; });
}, (error) => { return false; });
}
Using react-native, I'm creating sub-Components within the parent App and providing their position to the array this.state.objLocation within the parent App.
I can get the initial location data into the array straight after the render, but because my subcomponents are draggable, each time they re-render on drag, it adds a new position object to the array.
I'd like to avoid this, and I thought that creating this.state = { firstRender: true } in the constructor and then using componentDidMount = () => { this.setState({ firstRender: false }) } after the first render would allow me to create a 'gate' to stop the addition of the extra position objects.
I can see that if I comment out //componentDidMount = () => { this.setState({ firstRender: false }) } then I will get multiple entries to my array but if it's included in the class I get absolutely none.
So possibly my interpretation of the render lifecycle and componentDidMount is incorrect?
Here is my code.
// App
import React, { Component } from 'react';
import { View, Text, } from 'react-native';
import styles from './cust/styles';
import Draggable from './cust/draggable';
const dataArray = [{num: 1,id: 'A',},{num: 2,id: 'B',},{num: 3,id: 'Z',}]
export default class Viewport extends Component {
constructor(props){
super(props);
this.state = {
dID : null,
objLocation: [],
firstRender: true,
};
}
render(){
return (
<View style={styles.mainContainer}>
<View style={styles.draggableContainer}>
<Text>Draggable Container</Text> {dataArray.map( d => { return(
<Draggable
id={d.id}
onLayout={ e=> this.onLayout(e)}
onPanResponderGrant={(dID) =>this.setState({ dID })}
onPanResponderRelease={() => this.setState({dID: null})} /> ) })}
<View style={[styles.findPoint ]} />
</View>
<View style={styles.infoBar}>
<Text>{this.state.dID ? this.state.dID : ''}</Text>{this.compFrame()}
</View>
</View>
);
}
onLayout = (e) => {
if ( e && this.state.firstRender) {
const n = e.nativeEvent.layout;
const position = {
width: n.width,
height: n.height,
x: n.x,
y: n.y
}
console.log(position);
this.setState({
objLocation: this.state.objLocation.concat([position])
});
}
}
componentWillMount = () => {
console.log("START");
}
compFrame = () => {
return(
this.state.objLocation.map( d => {<View style={[styles.findPoint2,{left: d.x, top: d.y, width: d.width, height: d.height} ]} ></View>})
)
}
componentDidMount = () => {
this.setState({firstRender: true })
console.log(this.state.objLocation.length);
}
}
// Draggable
import React, { Component } from 'react';
import { Text, PanResponder, Animated } from 'react-native';
import styles from './styles';
class Draggable extends Component {
constructor(props) {
super(props);
this.state = {
pan: new Animated.ValueXY(),
};
this.panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderGrant: () => {
this.props.onPanResponderGrant(this.props.id);
},
onPanResponderMove: Animated.event([ null, {
dx: this.state.pan.x,
dy: this.state.pan.y,
},
]),
onPanResponderRelease: () => {
Animated.spring(this.state.pan, { toValue: { x: 0, y: 0 } }).start();
this.props.onPanResponderRelease();
},
});
}
render() {
return (
<Animated.View
onLayout={ (e) => this.props.onLayout(e) }
{...this.panResponder.panHandlers}
style={[this.state.pan.getLayout(), styles.circleAlt, styles.position]}>
<Text style={styles.textAlt}>Drag me!</Text>
<Text style={styles.textNum}>{this.props.id}</Text>
</Animated.View>
);
}
componentDidMount = () => {
this.props.onLayout(this.props.dragEvent)
}
}
export default Draggable;
// Output of console.log
START xxx
0
{width:108,height:108,x:133.5,y:376.5}
{width:108,height:108,x:133.5,y:78.5}
{width:108,height:108,x:133.5,y:227.5}
You could set the firstRender state in onLayout function
onLayout = (e) => {
if ( e && this.state.firstRender) {
const n = e.nativeEvent.layout;
const position = {
width: n.width,
height: n.height,
x: n.x,
y: n.y
}
console.log(position);
this.setState({
firstRender: false,
objLocation: this.state.objLocation.concat([position])
});
}
}
According to the information provided by you, your onLayout function is called by the component so its not included in the component lifecycle process, so when the component completes its lifecycle it goes into componentDidMount after mounting (which is not calling onLayout func) & thus changed the firstRender state to false and hence when you drag the component each time it goes from true to false.
I hope this explains
I feel like I've hacked this, to get it to work, so please correct me as to correct procedure.
This is the onLayout method from the App. I've included an if statement that checks if the new positions array length is equal too the dataArray length that the draggable items are based on.
It looks like this.
onLayout = (e) => {
if ( this.state.objLocation.length != dataArray.length ) {
if ( e ) {
const n = e.nativeEvent.layout;
const position = {
width: n.width,
height: n.height,
x: n.x,
y: n.y
}
console.log(position);
this.setState({
objLocation: this.state.objLocation.concat([position])
});
}
}
}
import React, { Component } from 'react';
import {
AppRegistry,
Button,
StyleSheet,
View,
requireNativeComponent,
} from 'react-native';
import Sketch from 'react-native-sketch';
const styles = StyleSheet.create({
container: {
flex: 1,
},
sketch: {
height: 250, // Height needed; Default: 200px
},
});
export default class paintChalledgeNative extends Component {
constructor(props) {
super(props);
this.clear = this.clear.bind(this);
this.onReset = this.onReset.bind(this);
this.onSave = this.onSave.bind(this);
this.onUpdate = this.onUpdate.bind(this);
this.state = {
drawing: null,
};
}
onReset() {
console.log('bye bye drawing');
}
onSave() {
this.sketch.saveImage(this.state.drawing)
.then(data => console.log(data))
.catch(error => console.log(error));
}
onUpdate(base64Image) {
this.setState({ drawing: base64Image });
}
clear() {
this.sketch.clear();
}
render() {
return (
<View style={styles.container}>
<Sketch
fillColor="transparent"
strokeColor="#111111"
strokeThickness={2}
imageType="png"
onReset={this.onReset}
onUpdate={this.onUpdate}
ref={(sketch) => { this.sketch = sketch; }}
style={styles.sketch}
/>
<Button
onPress={this.clear}
title="clear drawing"
/>
<Button
disabled={!this.state.encodedSignature}
onPress={this.onSave}
title="Save drawing"
/>
</View>
);
}
}
AppRegistry.registerComponent('paintChalledgeNative', () => paintChalledgeNative);
building sketch app using 'react-native-sketch' the simulator is running but the sketch feature is not woking at all and the clear button crashes the app with and error in the image , the console is logging 20 similar error msgs to the one below
'In file included from /Users/waltershub/Desktop/paintChalledgeNative/node_modules/react-native-sketch/RNSketch/RNSketch.m:11:
../react-native/React/Base/RCTEventDispatcher.h:18:3: error: redefinition of enumerator 'RCTTextEventTypeChange'
RCTTextEventTypeChange,'
I think it's because you've used the 0.5 version of react-native-sketch, which wasn't compatible with React Native > 0.40. Since then, a new 1.0 version has been published, so maybe you could try again with this one?
(Disclaimer: I'm the maintainer of react-native-sketch)