I am facing an error trying to implement Stripe payment with react native and Expo SDK.
The scenario is very simple where I add items to the cart and then choose payment option as card to pay, but when I click on Card an error shows up. the error and code are below.
import { StatusBar } from "expo-status-bar";
import React from "react";
import {
StyleSheet,
Text,
View,
Button,
Pressable,
Platform,
} from "react-native";
import { StripeProvider } from "#stripe/stripe-react-native";
import { initStripe, useStripe } from "#stripe/stripe-react-native";
import GooglePayMark from "./GooglePayMark";
import ApplePayMark from "./ApplePayMark";
const API_URL = "http://192.168.0.163:3000";
const ProductRow = ({ product, cart, setCart }) => {
const modifyCart = (delta) => {
setCart({ ...cart, [product.id]: cart[product.id] + delta });
};
return (
<View style={styles.productRow}>
<View style={{ flexDirection: "row" }}>
<Text style={{ fontSize: 17, flexGrow: 1 }}>
{product.name} - {product.price}$
</Text>
<Text style={{ fontSize: 17, fontWeight: "700" }}>
{cart[product.id]}
</Text>
</View>
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
marginTop: 8,
}}
>
<Button
disabled={cart[product.id] <= 0}
title="Remove"
onPress={() => modifyCart(-1)}
/>
<Button title="Add" onPress={() => modifyCart(1)} />
</View>
</View>
);
};
const ProductsScreen = ({ products, navigateToCheckout }) => {
/**
* We will save the state of the cart here
* It will have the inital shape:
* {
* [product.id]: 0
* }
*/
const [cart, setCart] = React.useState(
Object.fromEntries(products.map((p) => [p.id, 0]))
);
const handleContinuePress = async () => {
/* Send the cart to the server */
const URL = `${API_URL}/create-payment-intent`;
const response = await fetch(URL, {
method: "POST",
headers: {
"Content-Type": "application-json",
},
body: JSON.stringify(cart),
});
/* Await the response */
const { publishableKey, clientSecret, merchantName } =
await response.json();
/* Navigate to the CheckoutScreen */
/* You can use navigation.navigate from react-navigation */
navigateToCheckout({
publishableKey,
clientSecret,
merchantName,
cart,
products,
});
};
return (
<View style={styles.screen}>
{products.map((p) => {
return (
<ProductRow key={p.id} product={p} cart={cart} setCart={setCart} />
);
})}
<View style={{ marginTop: 16 }}>
<Button title="Continue" onPress={handleContinuePress} />
</View>
</View>
);
};
/**
* CheckoutScreen related components
*/
const CartInfo = ({ products, cart }) => {
return (
<View>
{Object.keys(cart).map((productId) => {
const product = products.filter((p) => p.id === productId)[0];
const quantity = cart[productId];
return (
<View
key={productId}
style={[{ flexDirection: "row" }, styles.productRow]}
>
<Text style={{ flexGrow: 1, fontSize: 17 }}>
{quantity} x {product.name}
</Text>
<Text style={{ fontWeight: "700", fontSize: 17 }}>
{quantity * product.price}$
</Text>
</View>
);
})}
</View>
);
};
const MethodSelector = ({ onPress, paymentMethod }) => {
// ...
return (
<View style={{ marginVertical: 48, width: "75%" }}>
<Text
style={{
fontSize: 14,
letterSpacing: 1.5,
color: "black",
textTransform: "uppercase",
}}
>
Select payment method
</Text>
{/* If there's no paymentMethod selected, show the options */}
{!paymentMethod && (
<Pressable
onPress={onPress}
style={{
flexDirection: "row",
paddingVertical: 8,
alignItems: "center",
}}
>
{Platform.select({
ios: <ApplePayMark height={59} />,
android: <GooglePayMark height={59} />,
})}
<View style={[styles.selectButton, { marginLeft: 16 }]}>
<Text style={[styles.boldText, { color: "#007DFF" }]}>Card</Text>
</View>
</Pressable>
)}
{/* If there's a paymentMethod selected, show it */}
{!!paymentMethod && (
<Pressable
onPress={onPress}
style={{
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
paddingVertical: 8,
}}
>
{paymentMethod.label.toLowerCase().includes("apple") && (
<ApplePayMark height={59} />
)}
{paymentMethod.label.toLowerCase().includes("google") && (
<GooglePayMark height={59} />
)}
{!paymentMethod.label.toLowerCase().includes("google") &&
!paymentMethod.label.toLowerCase().includes("apple") && (
<View style={[styles.selectButton, { marginRight: 16 }]}>
<Text style={[styles.boldText, { color: "#007DFF" }]}>
{paymentMethod.label}
</Text>
</View>
)}
<Text style={[styles.boldText, { color: "#007DFF", flex: 1 }]}>
Change payment method
</Text>
</Pressable>
)}
</View>
);
};
const CheckoutScreen = ({
products,
navigateBack,
publishableKey,
clientSecret,
merchantName,
cart,
}) => {
// We will store the selected paymentMethod
const [paymentMethod, setPaymentMethod] = React.useState();
// Import some stripe functions
const { initPaymentSheet, presentPaymentSheet, confirmPaymentSheetPayment } =
useStripe();
// Initialize stripe values upon mounting the screen
React.useEffect(() => {
(async () => {
await initStripe({
publishableKey,
// Only if implementing applePay
// Set the merchantIdentifier to the same
// value in the StripeProvider and
// striple plugin in app.json
merchantIdentifier: "yourMerchantIdentifier",
});
// Initialize the PaymentSheet with the paymentIntent data,
// we will later present and confirm this
await initializePaymentSheet();
})();
}, []);
const initializePaymentSheet = async () => {
const { error, paymentOption } = await initPaymentSheet({
paymentIntentClientSecret: clientSecret,
customFlow: true,
merchantDisplayName: merchantName,
style: "alwaysDark", // If darkMode
googlePay: true, // If implementing googlePay
applePay: true, // If implementing applePay
merchantCountryCode: "ES", // Countrycode of the merchant
testEnv: __DEV__, // Set this flag if it's a test environment
});
if (error) {
console.log(error);
} else {
// Upon initializing if there's a paymentOption
// of choice it will be filled by default
setPaymentMethod(paymentOption);
}
};
const handleSelectMethod = async () => {
const { error, paymentOption } = await presentPaymentSheet({
confirmPayment: false,
});
if (error) {
alert(`Error code: ${error.code}`, error.message);
}
setPaymentMethod(paymentOption);
};
const handleBuyPress = async () => {
if (paymentMethod) {
const response = await confirmPaymentSheetPayment();
if (response.error) {
alert(`Error ${response.error.code}`);
console.error(response.error.message);
} else {
alert("Purchase completed!");
}
}
};
return (
<View style={styles.screen}>
<CartInfo cart={cart} products={products} />
<MethodSelector
onPress={handleSelectMethod}
paymentMethod={paymentMethod}
/>
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
alignSelf: "stretch",
marginHorizontal: 24,
}}
>
<Pressable onPress={navigateBack}>
<Text style={[styles.textButton, styles.boldText]}>Back</Text>
</Pressable>
<Pressable style={styles.buyButton} onPress={handleBuyPress}>
<Text style={[styles.boldText, { color: "white" }]}>Buy</Text>
</Pressable>
</View>
</View>
);
};
const AppContent = () => {
const products = [
{
price: 10,
name: "Pizza Pepperoni",
id: "pizza-pepperoni",
},
{
price: 12,
name: "Pizza 4 Fromaggi",
id: "pizza-fromaggi",
},
{
price: 8,
name: "Pizza BBQ",
id: "pizza-bbq",
},
];
const [screenProps, setScreenProps] = React.useState(null);
const navigateToCheckout = (screenProps) => {
setScreenProps(screenProps);
};
const navigateBack = () => {
setScreenProps(null);
};
return (
<View style={styles.container}>
{!screenProps && (
<ProductsScreen
products={products}
navigateToCheckout={navigateToCheckout}
/>
)}
{!!screenProps && (
<CheckoutScreen {...screenProps} navigateBack={navigateBack} />
)}
</View>
);
};
export default function App() {
return (
<StripeProvider>
<AppContent />
</StripeProvider>
);
}
so having this code I was able to get the application running and the items were added to the cart but when I click on card option the error shows up.
I believe the error is generated at the CheckoutScreen.
error showing
Looks like this is what happened:
Your code invoked presentPaymentSheet.
It internally invoked flowController?.presentPaymentOptions.
It checked and found FlowController wasn't properly initialized and emit that
error.
The reason FlowController is not properly initialized is because there was null or empty client secret passed in. You would want to check if your clientSecret variable from navigateToCheckout actually had a value.
Related
We are currently developing based on React Native.
And I received data by GET request through API document,
and I created scroll view through MAP method.
So now I'm trying to make it possible to choose,
but if I choose one, it's all chosen.
How can I make you choose one by one if I choose one from my code?
import React, { useEffect, useState } from "react";
import { SvgCssUri } from "react-native-svg";
import { DeviceEventEmitter } from "react-native";
import {
View,
StyleSheet,
TouchableHighlight,
Text,
ScrollView,
Image,
} from "react-native";
import {
widthPercentageToDP as wp,
heightPercentageToDP as hp,
} from "react-native-responsive-screen";
import axios from "axios";
import BouncyCheckbox from "react-native-bouncy-checkbox";
const Select = ({ navigation }) => {
let bouncyCheckboxRef = null;
const [bodyType, setBodyType] = useState([]);
const [standardSelected, setStandardSelected] = useState(false);
const [isSelected, setSelected] = useState(false);
const bodyGetData = async () => {
let body = [];
try {
let config = {
method: "get",
url:
"http://everyweardev-env.eba-azpdvh2m.ap-northeast-2.elasticbeanstalk.com/api/v1/user/bodyType/male",
headers: {},
};
axios(config).then(function (response) {
response.data.data.map((u) => {
switch (u.bodyType) {
case "standard":
body.push({ bodyType: "스탠다드", imgUrl: u.imgUrl, key: 1 });
break;
case "reverseTriangle":
body.push({ bodyType: "역삼각형", imgUrl: u.imgUrl, key: 2 });
break;
case "triangle":
body.push({ bodyType: "삼각형", imgUrl: u.imgUrl, key: 3 });
break;
case "circle":
body.push({ bodyType: "원형", imgUrl: u.imgUrl, key: 4 });
break;
case "hourglass":
body.push({ bodyType: "직사각형", imgUrl: u.imgUrl, key: 5 });
break;
}
});
return setBodyType(body);
});
} catch (err) {
console.log(err);
}
};
useEffect(() => {
const unsubscribe = navigation.addListener("focus", () => {
bodyGetData();
});
return unsubscribe;
}, [navigation]);
const onClick = (e) => {
console.log(e);
bodyType.map((u) => {
switch (u.bodyType) {
case u.bodyType === "스탠다드":
setSelected(!isSelected);
console.log(isSelected);
break;
case "역삼각형":
setSelected(!isSelected);
break;
}
});
};
return (
<View style={styles.container}>
<Text
style={{ fontSize: wp("5.5%"), fontWeight: "bold", marginBottom: 21 }}
>
자신의 체형을 선택해 주세요
</Text>
<View style={{ flexDirection: "row", marginBottom: hp("10%") }}>
<Text style={{ fontSize: wp("4.5%"), marginRight: wp("1%") }}>
더 정확한 평가를 받으실 수 있습니다
</Text>
<Image
source={require("../../images/smile.png")}
style={{ marginTop: hp("0.5%") }}
/>
</View>
<ScrollView horizontal={true} showsHorizontalScrollIndicator={true}>
{bodyType.map((data) => (
<>
<TouchableHighlight
style={styles.bodySelect}
value={data.bodyType}
onPress={onClick}
// onPress={() => bouncyCheckboxRef?.onPress()}
>
<>
<BouncyCheckbox
isChecked={!isSelected}
ref={(ref) => (bouncyCheckboxRef = ref)}
size={25}
fillColor="black"
unfillColor="#FFFFFF"
iconStyle={{ borderColor: "white" }}
textStyle={{ fontFamily: "JosefinSans-Regular" }}
disableBuiltInState
onPress={onClick}
style={{
alignSelf: "flex-start",
marginLeft: wp("3%"),
marginTop: hp("2%"),
}}
/>
<SvgCssUri
uri={data.imgUrl}
width="90%"
height="60%"
marginTop="-5%"
key={data.key}
/>
<Text style={styles.bodytype}>{data.bodyType}</Text>
</>
</TouchableHighlight>
</>
))}
</ScrollView>
<TouchableHighlight
style={styles.button}
onPress={() => {
navigation.navigate("얼굴형 정보 입력");
}}
underlayColor="gray"
>
<>
<Text style={styles.text}>선택 완료</Text>
</>
</TouchableHighlight>
</View>
);
};
const styles = StyleSheet.create({
container: {
justifyContent: "center",
alignItems: "center",
marginTop: hp("5%"),
},
button: {
justifyContent: "center",
alignItems: "center",
width: wp("70%"),
height: hp("7%"),
color: "white",
backgroundColor: "black",
borderRadius: 10,
marginTop: hp("17%"),
},
text: {
color: "white",
fontSize: wp("5.2%"),
fontWeight: "bold",
},
bodySelect: {
marginLeft: 16,
marginRight: 16,
width: wp("70%"),
height: hp("35%"),
alignItems: "center",
borderRadius: 30,
backgroundColor: "#ffffff",
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 3,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
},
bodytype: {
marginTop: hp("3%"),
fontWeight: "bold",
fontSize: wp("8%"),
},
});
export default Select;
this example explain how to select individual choice.
do these steps :
//define state to save selected value inside it
const [selected, setSelected] = React.useState();
//handle item onPress
const onPress = (item) => {
setSelected(item);
}
//check if item selected
const isSelected = (item) => {
return selected?.unique_id === item.unique_id;
}
//and in render function
<ScrollView>
{
data.map((item, index) => {
return(
<ItemComponent
onPress={() => setSelected(item)}
style={isSelected(item) ? selectedStyle : defaultStyle}>
</ItemComponent>
)
})
}
</ScrollView>
full code try snack here
import * as React from 'react';
import { Text, View, StyleSheet, ScrollView, TouchableOpacity} from 'react-native';
export default function App() {
const [selected, setSelected] = React.useState();
const data = [
{
unique_id : 1,
text : "item one"
},
{
unique_id : 2,
text : "item two"
},
{
unique_id : 3,
text : "item three"
},
{
unique_id : 4,
text : "item four"
}
];
const onPress = (item) => {
setSelected(item);
}
const isSelected = (item) => {
return selected?.unique_id === item.unique_id;
}
return (
<ScrollView>
{
data.map((item, index) => {
return(
<TouchableOpacity
key={item.unique_id}
onPress={() => {
setSelected(item);
}}
style={{
padding : 25,
margin : 10,
backgroundColor : isSelected(item) ? "red" : "#eee"
}}
>
<Text>{item.text}</Text>
</TouchableOpacity>
)
})
}
</ScrollView>
);
}
Good day,
I have had an issue recently whereby I have been running an SQL script in an app I have developed. The app uses a Transient database and has been working absolutely flawlessly for some time.
What I originally wanted to happen is that the app uses fetch process to perform a listing of a related servers contents and presents them into a Fragment (However I didn't get this far) . I was in the middle of the development of the code when the DB got a little strange.
Seemingly overnight I seem to have lost control of the database, for a reason that I cannot fathom, the database is automatically and repeatedly inserting hundreds off nulls into the db and I have no idea why. I have checked, double checked, triple checked the code and isolated code blocks that I think could be causing the problem to no avail. The only change I have made recently before the issue occurred is inserting a Fragment into the page.
The App uses an old Todo list to access the SQL server. I believe the open database code could be the problem and have moved it slightly to try and alleviate the issue
Here is my code
import React, { Fragment, useState } from 'react';
import { ScrollView, StyleSheet, Text, TextInput, Button,TouchableOpacity, View,Image, CheckBox, Alert } from 'react-native';
import Constants from 'expo-constants';
import * as SQLite from 'expo-sqlite';
import { enableProdMode } from '#angular/core';
import {fetch} from 'node-fetch';
let ref = React.createRef()
function performGetRequest(){
const db = SQLite.openDatabase('db.db')
const getPage= {
getServerPage :(
fetch('TEST SERVER CURRENTLY DOWN')
.then(res => res.text())
.then(json=> console.log(json)))
}
}
const db = SQLite.openDatabase('db.db')
const list = {
Page :(
<Fragment>
TEST
</Fragment>
)
}
function Items({ done: doneHeading, onPressItem }) {
const [items, setItems] = React.useState(null);
React.useEffect(() => {
db.transaction(tx => {
tx.executeSql(
`select * from items where done = ?;`,
[doneHeading ? 1 : 0],
(_, { rows: { _array } }) => setItems(_array)
);
});
}, []);
const heading = doneHeading ? "Completed" : "Todo";
return null;
return (
<View style={styles.sectionContainer}>
<Text style={styles.sectionHeading}>{heading}</Text>
{items.map(({ id, done, value }) => (
<TouchableOpacity
key={id}
onPress={() => onPressItem && onPressItem(id)}
style={{
backgroundColor: done ? "#000000" : "#fff",
borderColor: "#000",
borderWidth: 1,
padding: 8
}}
>
<Text style={{ color: done ? "#fff" : "#000" }}>{value}</Text>
</TouchableOpacity>
))}
</View>
);}
function App() {
const [text, setText] = React.useState(null)
const [forceUpdate, forceUpdateId] = useForceUpdate()
React.useEffect(() => {
db.transaction(tx => {
tx.executeSql(
"create table if not exists items (id integer primary key not null, done int, value text);"
);
});
}, []);
const add = (text) => {
// is text empty?
if (text === null || text === "") {
return false;
}
}
db.transaction(
tx => {
tx.executeSql("insert into items (done, value) values (0, ?)", []);
tx.executeSql("select * from items", [], (_, { rows }) =>
console.log(JSON.stringify(rows))
);
},
null,
forceUpdate
);
let ref = React.createRef();
const Home: React.FC = () => {
let cancelToken: any = axios.CancelToken;
let source = cancelToken.source();
useEffect(() => {
(async () => {
try {
const data = await axios.get("https://Kitchkar.pagekite.me/music", {
cancelToken: source.token
});
}catch (error) {
if (axios.isCancel(error)) {
console.log('Request canceled', error.message);
} else {
// handle error
console.log(error);
}
}
})();
return () => {
//when the component unmounts
console.log("component unmounted");
// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');
}
}, []); //End UseEffect
};
return (
<View style={styles.container}>
<Text style={styles.heading}>Page Listing</Text>
<View style={styles.flexRow}>
<TextInput
onChangeText={text => setText(text)}
onSubmitEditing={() => {
add(text);
setText(null);
}}
placeholder="what do you need to do?"
style={styles.input}
value={text}
/>
</View>
<View style={{ width: 200}}>
<Button
title="Enter!"
color="gold"
width="100"
height="100"
onpress={(performGetRequest)}/>
</View>
<Text style={styles.heading}>server contents</Text>
<Text style={styles.heading}>{getPage.getServerPage}</Text>
<Text style={styles.heading}></Text>
<Items
key={`forceupdate-todo-${forceUpdateId}`}
done={false}
onPressItem={id =>
db.transaction(
tx => {
tx.executeSql(`update items set done = 1 where id = ?;`, [
id
]);
},
null,
forceUpdate
)
}
/>
<ScrollView style={styles.container}>
<Image source={require('Substitute any image here')}/>
<View style={{
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'flex-start',
}}>
<View style={{width: 200, height: 200, backgroundColor: 'yellow'}} />
<View style={{width: 200, height: 200, backgroundColor: 'orange'}} />
<View style={{width: 200, height: 200, backgroundColor: 'gold'}} />
</View>
<Text style={styles.heading}>Search History</Text>
<Items
done
key={`forceupdate-done-${forceUpdateId}`}
onPressItem={id =>
db.transaction(
tx => {
tx.executeSql(`delete from items where id = ?;`, [id]);
},
null,
forceUpdate
)
}
/>
<Text style={styles.heading}>Search History</Text>
</ScrollView>
</View>
);
}
function useForceUpdate() {
const [value, setValue] = useState(0);
return [() => setValue(value + 1), value];
}
db.transaction(
tx => {
tx.executeSql("select * from items", [], (_, { rows }) =>
tx.executeSql("insert into items (done, value) values (0, ?)", [console.log(JSON.stringify(rows))]));
}
);
const styles = StyleSheet.create({
container: {
color:"#FFD700",
},
button: {
width: "200",
height:"100",
},
heading: {
color: "#FFD700",
fontSize: 20,
fontWeight: "bold",
textAlign: "center"
},
flexRow: {
flexDirection: "row"
},
input: {
color:"#FFD700",
borderColor: "#FFD700",
borderRadius: 4,
borderWidth: 1,
flex: 1,
height: 48,
margin: 16,
padding: 8
},
})
export default App;
const db = SQLite.openDatabase('db.db') should be const db = SQLite.openDatabase("db.db");
I've implemented an app based on react native. This app shows me a list via swipelistview. But I have a Problem. when list add new items after scroll down, swipelistview won't work properly. In fact it works by Accident. I don't know where i've made mistake.
this is my code:
import React , {Component} from 'react';
import { StyleSheet, Text, View, FlatList ,ActivityIndicator,Animated , TouchableOpacity, Alert } from 'react-native';
import { SwipeListView } from 'react-native-swipe-list-view';
import { Container, Header, Content, Accordion ,Icon ,Item, Input , Button ,ActionSheet , Card, CardItem, Body} from "native-base";
var DESTRUCTIVE_INDEX = 3;
var CANCEL_INDEX = 4;
class App extends Component {
constructor(props) {
super(props);
this.actionSheet = null;
}
state = {
data: [],
filteredData: [],
page: 1,
loading: false,
error: null,
spinner: false,
searchText:'',
lety:false,
refreshing: false
};
componentDidMount() {
console.disableYellowBox = true;
this.fetchData();
}
handleLoadMore = () => {
this.setState(
{
page: this.state.page + 1
},
() => {
this.fetchData();
}
);
};
fetchData = () => {
const page = this.state.page;
this.setState({ loading: true });
let response = fetch(
'http://webgispro.ir/home/GetWords/' + page ,
{
method: "POST"
}
).then((response) => response.json())
.then((responseJson) => {
this.setState(
{
data : page === 1 ? Array.from(responseJson): [...this.state.data, ...responseJson] ,
loading: false,
refreshing: false
})
})
.catch((error) => {
this.setState({ error, loading: false });
});
};
searchData = (searchText) => {
this.setState({searchText: searchText.toLowerCase()});
if (searchText =='') {
this.setState({filteredData: []});
this.setState({lety:false})
return false;
}
let filteredData = this.state.data.filter(function (item) {
return item.Word.toLowerCase().includes(searchText.toLowerCase());
});
this.setState({lety : filteredData.length == 0 ? true : false})
this.setState({filteredData: filteredData});
};
renderHeader = () => {
return <Searchbar
style={{ width:'100%' }}
inputStyle={{borderWidth: 0}}
round={false}
lightTheme={true}
placeholder="Search..."
autoCapitalize='none'
autoCorrect={false}
onChangeText={this.searchData}
value={this.state.searchText}
/>
};
renderFooter = () => {
if (!this.state.loading) return null;
return (
<View
style={{
paddingVertical: 20,
borderTopWidth: 1,
borderColor: "#CED0CE"
}}
>
<ActivityIndicator animating ={true} color="blue" style={{height: 80, marginTop: 10, opacity: 1 }} size="large" />
</View>
);
};
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: "100%",
backgroundColor: "#CED0CE",
//marginLeft: "14%"
}}
/>
);
};
handleRefresh = () => {
this.rowHeightAnimatedValues = {};
this.setState(
{
page: 1,
refreshing: true
},
() => {
this.fetchData();
}
);
};
editItem = key => () => {
var example = this.state.data.find(o=>o.Id == key).Example
if ( this.actionSheet !== null ) {
const title = <Text style={{ color: 'black', fontSize: 23 }}>{example}</Text>
this.actionSheet._root.showActionSheet(
{
options: [] ,
cancelButtonIndex: CANCEL_INDEX,
destructiveButtonIndex: DESTRUCTIVE_INDEX,
title:title
}, (i) => console.log(i));
}
}
deleteItem = key => () => {
Alert.alert(
"???",
"??? ???? ??? ????? ????? ??",
[
{
text: "???",
onPress: () => console.log("Cancel Pressed"),
style: "cancel"
},
{ text: "???", onPress: () => console.log("OK Pressed") }
],
{ cancelable: false }
);
}
onRowOpen =() => {
console.log('cfdfdf')
}
render() {
return (
<View style={styles.container}>
<Header searchBar rounded>
<Item>
<Icon name="ios-search" />
<Input placeholder="Search" onChangeText={this.searchData} />
<Icon name="ios-people" />
</Item>
<Button transparent>
<Text>Search</Text>
</Button>
</Header>
<SwipeListView
useFlatList
extraData={this.state}
data={this.state.filteredData && this.state.filteredData.length > 0 || this.state.lety == true ? this.state.filteredData : this.state.data}
keyExtractor={item => item.Id.toString()}
renderItem={(data, rowMap) => (
<Animated.View
style={[
styles.rowFront,
data.index % 2 === 0 && { backgroundColor: 'white' },
{ height: 100 }
]}
>
<Text style={{position: 'absolute', top: 35 , fontSize:20}}>
{data.item.Word}
</Text>
</Animated.View>
)}
renderHiddenItem={ (data, rowMap) => (
<View style={styles.rowBack}>
<Text style={{fontSize:20}}>{data.item.Meaning}</Text>
<TouchableOpacity style={[styles.backRightBtn, styles.backRightBtnLeft]} onPress={this.editItem(data.item.Id)}>
<Icon name='md-information-circle-outline' />
</TouchableOpacity>
<TouchableOpacity style={[styles.backRightBtn, styles.backRightBtnRight]} onPress={this.deleteItem(data.item.Id)}>
<Icon name='trash-outline' />
</TouchableOpacity>
</View>
)}
leftOpenValue={90}
rightOpenValue={-150}
onEndReached={this.handleLoadMore}
onEndReachedThreshold={0.5}
initialNumToRender={8}
ItemSeparatorComponent={this.renderSeparator}
ListFooterComponent={this.renderFooter}
onRefresh={this.handleRefresh}
refreshing={this.state.refreshing}
/>
<ActionSheet ref={(c) => { this.actionSheet = c; }} />
</View>
);
}
}
export default App
const styles = StyleSheet.create({
container: {
backgroundColor: 'white',
flex: 1,
//paddingTop: 50,
},
backTextWhite: {
color: '#FFF'
},
rowFront: {
alignItems: 'center',
backgroundColor: '#CCC',
justifyContent: 'center',
},
rowBack: {
alignItems: 'center',
backgroundColor: 'green',
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
paddingLeft: 15,
},
backRightBtn: {
alignItems: 'center',
bottom: 0,
justifyContent: 'center',
position: 'absolute',
top: 0,
width: 75
},
backRightBtnLeft: {
backgroundColor: 'blue',
right: 75
},
backRightBtnRight: {
backgroundColor: 'red',
right: 0
},
});
The list works properly and comes data but whenever I scroll down or up it doesn't work anymore. Please help me
If you are in mindset to change your package, then you can try react-native-snap-carousel, perfect for your requirement. Thanks
I'm trying to do a connection to a device with BLE.
I need to connect to a specific device automatically.
I don't understand how I can do to connect directly to a device. Let me explain better, at the moment I can scan and I get all the bluetooth devices. Instead, I would like to directly connect to a specific device.
- I should therefore select only one type of device
- Connect me directly
What do you think I can do?
With this code i choose the name
return (
<View style={{borderBottomColor: 'lightgrey', borderBottomWidth: 1, alignItems: 'stretch'}}>
<View style={{flexDirection: 'row', alignItems: 'center', padding: 15}}>
<View style={{flex: 1}}>
<Text style={{fontSize: 20, color: '#888'}}>{`${peripheral.name}`}</Text>
</View>
<View style={{flexDirection: 'row', justifyContent: 'flex-end'}}>
<Btn onPress={() => onConnect(peripheral)}>
{`Connect`}
</Btn>
</View>
</View>
</View>
)
With this code I do the scan
return (
<View style={{flex: 1 , paddingTop: Theme.navbarHeight }}>
<StatusBar
/* backgroundColor={Theme.color}*/
/* barStyle="light-content" */
/>
{
Object.keys(peripherals).length === 0 ? (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
{ uiState === UiState.scanning && <ActivityIndicator size='large' color={Theme.color}/> }
<Text style={{marginBottom: 10, fontSize: 18, color: '#999'}}>
Nessun Risultato
</Text>
{ uiState === UiState.idle && <Btn onPress={this._doScan}>Scansione</Btn> }
</View>
) : (
<ScrollView style={{ flex: 1 }} contentContainerStyle={{ alignItems: 'stretch' }}>
{
Object.keys(peripherals).map(key => peripherals[key]).map(
peripheral => (
<Peripheral
key={peripheral.id}
peripheral={peripheral}
onConnect={onConnect}
/>
)
)
}
</ScrollView>
)
}
</View>
)
}
_renderScanButton = () => {
let {uiState} = this.state;
if (uiState === UiState.scanning) {
return <ActivityIndicator color='white'/>
}
return (
<TouchableOpacity onPress={this._doScan}>
<Text style={{color: 'white', width: 100, textAlign: 'right'}}>Scansione</Text>
</TouchableOpacity>
)
}
_doScan = () => {
if (this.state.uiState !== UiState.idle) {
return;
}
this.setState({ uiState: UiState.scanning, peripherals: {} });
BleManager.scan([], 5, true)
.then(results => {
console.log('Scansione in corso...');
})
.catch(() => {
this.setState({ uiState: UiState.idle })
})
}
}
You are using react-native-ble-manager. According to their docs, you can connect to a peripheral using the connect method:
BleManager.connect('XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX')
.then(() => {
// Success code
console.log('Connected');
})
.catch((error) => {
// Failure code
console.log(error);
});
You should get the peripheral UID from the scan method results:
BleManager.scan([], 5, true)
.then(results => {
// Success code
console.log(results);
});
I personally do not use the react-native-ble-manager package but the react-native-ble-plx package, but the process is pretty similar. Here's how I do it:
manager.startDeviceScan(null, null, async (error, device) => {
console.log("scanning bluetooth...")
if (device.name === "MY_DEVICE_NAME") {
manager
.connectToDevice(device.id, {
autoconnect: true,
timeout: BLUETOOTH_TIMEOUT
})
// ............
}
})
I'm working on a news app, and this is the news details screens, it renders all the news details but i want to render the next news below this one when the end is reached. I can manage to get the new news details by using isCloseToBottom method and i can render the new news but the old one get replaced, but i don't want the old news to disappear. Is there any workaround for this?
class NewsDetails extends React.Component {
constructor(props) {
super(props);
this.state = {
visible: false,
loaded: false,
article: {},
request_control:1
};
}
componentWillMount() {
const { params } = this.props.navigation.state;
console.log(params.id);
axios
.get(`${URL_NEWS_DETAILS}/${params.id}`)
.then(response =>
this.setState({
article: response.data,
loaded: true,
})
)
.catch(error => console.log(error));
}
_onRefresh=()=>{
this.setState({refreshing: true})
axios.get(`${URL_NEWS_DETAILS}/210971`) //test with constant id
.then(response =>
this.setState({
article: response.data,
loaded: true,
})
)
.catch(error => console.log(error));
this.setState({refreshing: false});
};
renderNext=()=>{
if(this.state.request_control===1) {
this.setState({request_control: 0});
axios.get(`${URL_NEWS_DETAILS}/210971`) //test with constant id
.then(response => {
this.setState({
request_control:1,
article: response.data,
loaded: true
})
},
)
.catch(error => {
this.setState({ loaded: true})
console.log(error)
})
}
};
render() {
if (this.state.loaded) {
return (
<View style={styles.container}>
<ScrollView showsVerticalScrollIndicator={false}
onScroll={({nativeEvent}) => {
if (isCloseToBottom(nativeEvent)) {
this.renderNext()
}
}}
scrollEventThrottle={400}
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this._onRefresh.bind(this)}
/>
}>
<Text style={styles.title}>
{this.state.article.title.rendered.replace("–", "-")}
</Text>
<View
style={{ marginTop: 10, marginBottom: 10, flexDirection: 'row', alignItems: 'center' }}>
<Image
style={{ width: 18, height: 18 }}
source={require('../../img/icon.png')}
/>
<Text style={{ fontFamily: 'Open Sans Bold', fontSize: 14 }}>
{' '}
{this.state.article.author}
</Text>
<Text style={{ fontFamily: 'Open Sans Regular', fontSize: 13 }}>
{' '}
në{' '}
</Text>
{this.state.article.categories.map(category => {
return (
<Text
style={{
fontFamily: 'Open Sans Regular',
fontSize: 13,
color: '#F33A22',
}}>
{category.name},{' '}
</Text>
);
})}
</View>
<Lightbox underlayColor="white">
<Image
style={styles.image}
source={{ uri: this.state.article.featured_image_url }}
/>
</Lightbox>
<HTMLView
value={'<div>' + this.state.article.content.raw + '</div>'}
renderNode={Platform.OS === 'android' ? this.renderNode : null}
stylesheet={htmlStyles}
/>
{/*HERE I NEED TO RENDER A NEW NEWS BELOW THE MAIN ONE, */}
{/*TO CREATE AN EFFECT LIKE USED IN WEB THAT DISPLAYS NEWS AFTER NEWS*/}
</ScrollView>
</View>
);
} else return <Spinner />;
}
}
Your state article is replaced by the new one when you call renderNext, so the old one get replaced. To fix that, just change like
renderNext=()=>{
if(this.state.request_control===1) {
this.setState({request_control: 0});
axios.get(`${URL_NEWS_DETAILS}/210971`) //test with constant id
.then(response => {
this.setState({
request_control:1,
article: [...this.state.article, ...response.data],
loaded: true
})
},
)
.catch(error => {
this.setState({ loaded: true})
console.log(error)
})
}
};