Component out of sync in React Native - javascript

I'm working with my React Native project where I have like a "form" in which the user selects what day and between what hours they're available. There are two components involved:
The parent one: It has two time selectors and the day selector component
The child one: This is the day selector component. It displays the days in the week so the user can select whatever days they want.
This is the DaySelector:
import * as React from "react";
import { View, Text, StyleSheet, Button, Alert } from "react-native";
import { TouchableOpacity } from "react-native-gesture-handler";
import colors from "../assets/constants/style-variables";
interface Item {
selected: Boolean;
day: String;
}
function Day(props) {
return (
<TouchableOpacity
onPress={props.onPress}
style={props.selected ? styles.buttonActive : styles.button}
>
<Text>{props.day}</Text>
</TouchableOpacity>
);
}
export default class DaySelector extends React.Component<
{ onChange },
{ selectedItems: undefined | Item[]; items: Item[] }
> {
constructor(props) {
super(props);
this.state = {
selectedItems: [],
items: [
{
selected: false,
day: "Lu",
},
{
selected: false,
day: "Ma",
},
{
selected: false,
day: "Mi",
},
{
selected: false,
day: "Ju",
},
{
selected: false,
day: "Vi",
},
{
selected: false,
day: "Sa",
},
{
selected: false,
day: "Do",
},
],
};
}
onPress = (index) => {
let items = [...this.state.items];
let item = { ...items[index] };
item.selected = !item.selected;
items[index] = item;
this.setState({ items });
this.setState((prevState) => ({
selectedItems: prevState.items.filter((i) => i.selected),
}));
this.props.onChange(this.state.selectedItems);
};
render() {
return (
<View>
<View style={styles.container}>
{this.state.items.map((item, index) => {
return (
<Day
key={index}
selected={item.selected}
day={item.day}
onPress={this.onPress.bind(this, index)}
/>
);
})}
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flexDirection: "row",
},
button: {
margin: 5,
borderColor: colors.lightGray,
borderWidth: 2,
borderRadius: 40,
padding: 7,
},
buttonActive: {
margin: 5,
borderColor: colors.primary,
borderWidth: 2,
backgroundColor: colors.primary,
borderRadius: 50,
padding: 7,
},
});
As you can see, it collects all the days selected and passes them into the onChange prop. That way I can access the results in my parent component, which is this one:
import React, { useState, useCallback, useReducer } from "react";
import { useMutation } from "#apollo/react-hooks";
import { REGISTER } from "../Queries";
import Loader from "../components/Loader";
import DateTimePicker from "#react-native-community/datetimepicker";
import { View, StyleSheet } from "react-native";
import colors from "../assets/constants/style-variables";
import { TouchableOpacity } from "react-native-gesture-handler";
import PrimaryText from "../assets/constants/PrimaryText";
import DaySelector from "../components/DaySelector";
function reducer(state, action) {
switch (action.type) {
case "refresh-days":
return {
dayList: action.value,
};
default:
return state;
}
}
export default function ScheduleSelect({ navigation, route }) {
const [loadingRegistration, setLoadingRegistration] = useState(null);
const [showTimePicker1, setShowTimePicker1] = useState(false);
const [showTimePicker2, setShowTimePicker2] = useState(false);
const [time1, setTime1] = useState(null);
const [time2, setTime2] = useState(null);
const [{ dayList }, dispatch] = useReducer(reducer, { dayList: [] });
const show1 = () => {
setShowTimePicker1(true);
};
const show2 = () => {
setShowTimePicker2(true);
};
const handleTimePick1 = (_event, selectedTime) => {
setShowTimePicker1(false);
if (selectedTime !== undefined) {
setTime1(selectedTime);
}
};
const handleTimePick2 = (_event, selectedTime) => {
setShowTimePicker2(false);
if (selectedTime !== undefined) {
setTime2(selectedTime);
}
};
return (
<View>
<View style={styles.container}>
<PrimaryText fontSize={20} margin={22} textAlign={"center"}>
Recibirás turnos en estos horarios:
</PrimaryText>
<View style={styles.cardHolder}>
<View style={styles.card}>
<View style={styles.timeHelper}>
<PrimaryText textAlign={"center"}>Desde</PrimaryText>
</View>
{time1 && (
<TouchableOpacity onPress={show1}>
<View style={styles.timeSelected}>
<PrimaryText textAlign={"center"} fontSize={36}>
{`${time1?.getHours()}:${
time1.getMinutes() < 10
? "0" + time1.getMinutes()
: time1.getMinutes()
}`}
</PrimaryText>
</View>
</TouchableOpacity>
)}
{!time1 && (
<TouchableOpacity style={styles.clockEdit} onPress={show1}>
<PrimaryText
fontSize={36}
letterSpacing={2}
textAlign={"center"}
>
--:--
</PrimaryText>
</TouchableOpacity>
)}
{showTimePicker1 && (
<DateTimePicker
value={new Date()}
testID="dateTimePicker"
mode={"time"}
is24Hour={true}
display="default"
onChange={handleTimePick1}
/>
)}
</View>
<PrimaryText fontSize={36} margin={7}>
-
</PrimaryText>
<View style={styles.card}>
<View style={styles.timeHelper}>
<PrimaryText textAlign={"center"}>Hasta</PrimaryText>
</View>
{time2 && (
<TouchableOpacity onPress={show2}>
<View style={styles.timeSelected}>
<PrimaryText textAlign={"center"} fontSize={36}>
{`${time2?.getHours()}:${
time2.getMinutes() < 10
? "0" + time2.getMinutes()
: time2.getMinutes()
}`}
</PrimaryText>
</View>
</TouchableOpacity>
)}
{!time2 && (
<TouchableOpacity style={styles.clockEdit} onPress={show2}>
<PrimaryText
fontSize={36}
letterSpacing={2}
textAlign={"center"}
>
--:--
</PrimaryText>
</TouchableOpacity>
)}
{showTimePicker2 && (
<DateTimePicker
value={new Date()}
testID="dateTimePicker"
mode={"time"}
is24Hour={true}
display="default"
onChange={handleTimePick2}
/>
)}
</View>
</View>
{time2?.getTime() < time1?.getTime() && (
<PrimaryText color={colors.warning}>
Por favor, seleccioná horarios válidos
</PrimaryText>
)}
<PrimaryText margin={5}> Los días: </PrimaryText>
<View style={styles.card}>
<DaySelector
onChange={(value) => dispatch({ type: "refresh-days", value })}
/>
</View>
</View>
<View style={styles.buttonWrapper}>
<TouchableOpacity
style={styles.button}
onPress={() => {
console.log(dayList);
}}
>
<PrimaryText color={colors.iceWhite}>SIGUIENTE</PrimaryText>
</TouchableOpacity>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
height: "88%",
justifyContent: "center",
paddingTop: 15,
alignItems: "center",
},
clockEdit: {
padding: 7,
},
button: {
alignSelf: "flex-end",
backgroundColor: colors.primary,
padding: 7,
margin: 15,
borderRadius: 15,
},
buttonWrapper: {
justifyContent: "flex-end",
alignItems: "flex-end",
paddingRight: 15,
},
card: {
flexDirection: "row",
justifyContent: "center",
minWidth: "35%",
backgroundColor: colors.iceWhite,
borderRadius: 10,
padding: 20,
marginBottom: 10,
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
},
cardHolder: {
flexDirection: "row",
alignItems: "center",
},
timeHelper: {
justifyContent: "center",
position: "absolute",
marginTop: 5,
},
timeSelected: {
alignItems: "center",
justifyContent: "center",
},
editIcon: {
right: 3,
top: 3,
position: "absolute",
},
});
The problem is that when I console.log the value of the onChange prop, I get the items out of sync. To try and solve this, you see that I used a reducer, since the task is dependent of the result of the action. However, it does not change anything and still returns "outdated" information.
How can I sync both of the components?

This problems might come from your setState in your first component. you are calling the setState and then use the state straight after. But setState is asynchronous. So when you call your onChange, the state is still the previous one.
The prototype of setState is
setState(callback: (currentState) => newState | newState, afterSetState: (newState) => void)
So you can use the afterSetState callback to receive the new state and call your props.onChange
Also you are calling setState twice, but you could call it once and manipulate the state to return all in one.
However, if I could give you an advice, it'd be better controlling the state from the parent instead of the child. It avoids you calling a setState in the child and call the onChange in the parent which will set the state somewhere else again.

Related

Improving React Native performance deactivating Component when not in use

I'm developing an app for tuning pianos in react-native. I have an App.js and some screens implemented with react-navigation. The question is, how i can deactivate (or just not render) a component Screen when the user isn't in that screen?
The idea is to catch when this Screen Component is the Active Screen (like using navigation props), i can activate the render and deactivate when the Active Screen changes.
The Tab.js, containing the tab screens.
import React from "react";
/** Screens */
import TunerScreen from "./tunerScreen";
import Inharmonicity from "./inharmonicityScreen";
import BeatsScreen from "./beatsScreen";
/** Navigation */
import { MaterialCommunityIcons } from "#expo/vector-icons";
import { createMaterialBottomTabNavigator } from "#react-navigation/material-bottom-tabs";
/** Tab */
const Tab = createMaterialBottomTabNavigator();
/* Tabs of screen */
export default Tabs = ({
handleSwitch,
beatsCalc,
inharmonicityCalc,
inharmonicitySave,
}) => {
return (
<Tab.Navigator activeColor="#000" barStyle={{ backgroundColor: "white" }}>
<Tab.Screen
...
/>
// This is the component screen trying to deactivate
<Tab.Screen
name="Beats"
children={() => (
<BeatsScreen beatsCalc={beatsCalc} />
)}
options={{
tabBarLabel: "Beats",
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons
name="blur-radial"
color="black"
size={26}
/>
),
}}
/>
<Tab.Screen
...
/>
</Tab.Navigator>
);
};
The BeatsScreen.js (component to deactivate).
import React, { Component, useState } from "react";
import { View, Text, Button, Switch } from "react-native";
import Note from "../src/components/note";
import { connect } from "react-redux";
import style from "../styles/style";
import Picker from "#gregfrench/react-native-wheel-picker";
var PickerItem = Picker.Item;
class BeatsScreen extends Component {
constructor(props) {
super(props);
this.state = {
beats: 0,
// Prima nota
firstNote: { name: "A", octave: 4, frequency: 440, selected: false },
// Seconda nota
secondNote: { name: "A", octave: 4, frequency: 440, selected: false },
// Elemento selezionato dal picker
selectedItem: 0,
// Elementi del picker
itemList: ["Terza", "Quarta", "Quinta", "Ottava", "Prima"],
};
}
beatsUpdate = () => {
this.state.beats = beatsCalc(
this.state.firstNote,
this.state.secondNote,
this.state.selectedItem
);
};
render() {
if (!this.state.firstNote.selected)
this.state.firstNote = this.props.note;
if (!this.state.secondNote.selected)
this.state.secondNote = this.props.note;
this.beatsUpdate();
return (
<View style={{ flex: 1, flexDirection: "column" }}>
<View style={{ flex: 1 }}>
<View style={{ flex: 1, flexDirection: "row" }}>
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<Note {...this.state.firstNote} />
<Text style={style.frequency}>
{this.state.firstNote.frequency.toFixed(1)} Hz
</Text>
{
<Switch
style={{
paddingTop: 50,
transform: [{ scaleX: 2 }, { scaleY: 2 }],
}}
value={this.state.firstNote.selected}
onValueChange={() => {
// Se la nota è stata selezionata
this.state.firstNote.selected =
!this.state.firstNote.selected;
}}
/>
}
</View>
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<Note {...this.state.secondNote} />
<Text style={style.frequency}>
{this.state.secondNote.frequency.toFixed(1)} Hz
</Text>
<Switch
style={{
paddingTop: 50,
transform: [{ scaleX: 2 }, { scaleY: 2 }],
}}
value={this.state.secondNote.selected}
onValueChange={() => {
// Se la nota è stata selezionata
this.state.secondNote.selected =
!this.state.secondNote.selected;
}}
/>
</View>
</View>
</View>
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<Picker
style={{ width: 150, height: 180 }}
lineColor="#000000" //to set top and bottom line color (Without gradients)
lineGradientColorFrom="#008000" //to set top and bottom starting gradient line color
lineGradientColorTo="#FF5733" //to set top and bottom ending gradient
selectedValue={this.state.selectedItem}
itemStyle={{ color: "black", fontSize: 26 }}
onValueChange={(index) => {
this.state.selectedItem = index;
this.beatsUpdate();
}}
>
{this.state.itemList.map((value, i) => (
<PickerItem label={value} value={i} key={i} />
))}
</Picker>
<Text style={{ fontSize: 18 }}>Battimenti: </Text>
<Text style={{ fontSize: 80, paddingTop: 1 }}>
{this.state.beats}
</Text>
</View>
</View>
);
}
}
/** Mappa lo stato (store) con le props, cosi' da poterle usare nel componente. */
const mapStateToProps = (state) => {
const { note } = state;
const { tunerSwitch } = state;
return { note, tunerSwitch };
};
const mapDispatchToProps = (dispatch) => {
return {
startAndStop: () => dispatch({ type: "SWITCH" }),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(BeatsScreen);
I think if you use this option on the init of the tab bar you could solve your issue https://reactnavigation.org/docs/bottom-tab-navigator/#detachinactivescreens

FlatList component is not showing result

I am working on a task in which I have to implement infinite scroll paging of 600 dummy records to cards I have coded on FlatList render. So far I have implemented logic using FlatList but not successfully. Help is required where I am doing wrong thus not giving result. Here is the component code:
import React, { Component } from "react";
import { StyleSheet, ActivityIndicator, FlatList, View } from "react-native";
import { Card } from "react-native-elements";
class InfiniteScroll extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
data: [],
dummy: [],
fetchingStatus: false,
setOnLoad: false,
};
this.page = 0;
let onEndReached = false;
}
componentDidMount() {
var toput = [];
for (let i = 0; i < 598; i++) {
toput.push({
name: "KHAN MARKET",
order_no: "ORDER # DBZ-876",
status: "Order Completed",
price: "Total: $14.00",
date: "Dec 19, 2019 2:32 PM",
});
}
this.setState(
{
dummy: toput,
},
() => {
console.log(this.state.dummy);
}
);
this.apiCall();
}
apiCall = () => {
var that = this;
var old = that.page;
that.page = that.page + 10;
console.log(" *********** call " + this.page);
that.setState({ fetchingStatus: true });
that.setState({
data: [...this.state.data, ...this.state.dummy.slice(old, that.page)],
isLoading: false,
fetchingStatus: false,
setOnLoad: true,
});
};
BottomView = () => {
return (
<View>
{this.state.fetchingStatus ? (
<ActivityIndicator
size="large"
color="#F44336"
style={{ marginLeft: 6 }}
/>
) : null}
</View>
);
};
ItemSeparator = () => {
return (
<View
style={{
height: 0.5,
width: "100%",
backgroundColor: "#607D8B",
}}
/>
);
};
render() {
return (
<View>
{this.state.isLoading ? (
<ActivityIndicator size="large" />
) : (
<FlatList
style={{ width: "100%" }}
keyExtractor={(item, index) => index}
data={this.state.data}
ItemSeparatorComponent={this.ItemSeparator}
onScrollEndDrag={() => console.log(" *********end")}
onScrollBeginDrag={() => console.log(" *******start")}
initialNumToRender={8}
maxToRenderPerBatch={2}
onEndReachedThreshold={0.1}
onMomentumScrollBegin={() => {
this.onEndReached = false;
}}
onEndReached={() => {
if (!this.onEndReached) {
this.apiCall(); // on end reached
this.onEndReached = true;
}
}}
renderItem={({ item, index }) => (
<View>
<Card>
<Text
style={{ justifyContent: "flex-start", fontWeight: "bold" }}
>
{item.name}
</Text>
<View style={styles.textview}>
<Text style={styles.orderno}>{item.order_no}</Text>
<Text style={styles.orderstatus}>{item.status}</Text>
</View>
<Text style={styles.amount}>{item.price}</Text>
<View style={styles.textview}>
<Text style={styles.orderno}>{item.date}</Text>
</View>
</Card>
</View>
)}
ListFooterComponent={this.BottomView}
/>
)}
</View>
);
}
}
const styles = StyleSheet.create({
textview: {
marginTop: 5,
flexDirection: "row",
justifyContent: "space-between",
},
orderno: {
flexDirection: "row",
justifyContent: "flex-start",
},
orderstatus: {
flexDirection: "row",
justifyContent: "flex-end",
color: "green",
},
ordercomplete: {
flexDirection: "row",
justifyContent: "flex-end",
color: "red",
},
amount: {
justifyContent: "flex-start",
marginTop: 5,
},
});
export default InfiniteScroll;
I will be very thankful if you can provide solution. Thanks
The thing here is that you are seting your dummy data and calling the apiCall next, the dummy data is not updated yet when you call the apiCall, ande the dummy data is shown as an empty array on the apiCall, you just ned to force some await before calling the function, just change from this:
this.setState(
{
dummy: toput,
},
() => {
console.log(this.state.dummy);
}
);
this.apiCall();
to this:
this.setState(
{
dummy: toput
},
() => {
this.apiCall();
}
);
Another thing I notice is that you are using some bad pratices like setting valuse direct on the class instead of using state and some messing with the scope (that = this), I've made some updates/suggestions in you code that may help with readability:
apiCall = () => {
const newPage = this.state.page + 10;
this.setState({
data: [
...this.state.data,
...this.state.dummy.slice(this.state.page, newPage)
],
isLoading: false,
fetchingStatus: false,
setOnLoad: true,
page: newPage
});
};
I've created a fully working example so you can see some more updates I've made in the code, that may help you as well:
https://codesandbox.io/s/stackoverflow-67166780-321ku?file=/src/App.js

How can i get back my data list after searching by words?

i use Flatlist and search by words on renderHeader() function. I can filter but when i delete letters, i couldn't get main list again. I think there is a logic problem but i couln't find after trying something...
i've got a new one when i fixed problem. I tried to fix but i couldn't do that, i should put the problem in front of experts :)
import React, {Component, useState} from 'react'
import {
Text,
StyleSheet,
View,
FlatList,
SafeAreaView,
ScrollView,
Image,
TextInput,
} from 'react-native'
import data from '../../data'
const Flatlistexample = () => {
//main list state
let [list, setList] = useState(data);
//search state
const [search, setSearch] = useState('');
//search filter
searchFilter = text => {
// onChangeText
const newData = list.filter(item => {
const listItem = `${item.name.toLowerCase()} ${item.company.toLowerCase()}`
return listItem.indexOf(text.toLowerCase()) > -1;
})
setList(newData)
}
//search function
renderHeader = () =>{
return (
<View style={styles.seachContainer}>
<TextInput
style={styles.textInput}
placeholder={'Search...'}
value={search}
onChangeText={text => {
//setStates
searchFilter(text)
setSearch(text)
}}></TextInput>
<Text
style={{
alignItems: 'flex-start',
color: 'black',
fontSize: 22,
}}>
{search}
</Text>
</View>
)
}
return (
<SafeAreaView
style={{
flex: 1,
}}>
<FlatList
data={list}
renderItem={({item, index}) => {
return (
<ScrollView>
<SafeAreaView
style={[
styles.container,
{backgroundColor: index % 2 === 0 ? '#fafafa' : '#bbb'},
]}>
<Image style={styles.profile} source={{uri: item.picture}} />
<View style={styles.rightside}>
<Text style={styles.name}>{item.name}</Text>
<Text style={styles.company}>{item.company}</Text>
</View>
</SafeAreaView>
</ScrollView>
)
}}
keyExtractor={item => item._id}
//called search function
ListHeaderComponent={renderHeader()}
/>
</SafeAreaView>
)
}
export default Flatlistexample
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
borderBottomWidth: 1,
borderColor: 'gray',
},
profile: {
width: 50,
height: 50,
borderRadius: 25,
marginLeft: 10,
},
rightside: {
marginLeft: 20,
justifyContent: 'space-between',
marginVertical: 5,
},
name: {
fontSize: 22,
marginBottom: 10,
},
searchContainer: {
padding: 10,
borderWidth: 2,
borderColor: 'gray',
},
textInput: {
fontSize: 16,
backgroundColor: '#f9f9f9',
padding: 10,
},
})
Thanks for your help
Filter Data
onSearchText = (value) => {
this.setState({searchText: value})
if(value.trim() == "" || value == null){
this.setState({list: this.state.list}
} else {
let filter = this.state.list.fillter(data => {
// data fillter logic //
return data;
})
this.setState({filterData: filter})
}
Render FlatList
<FlatList
extradata={this.state}
data={searchText ? filterData : list}
/>
I fixed...
How?
My main data state is constant, i'm filtering on data list with filter state. So my data list doesn't change anytime.
import React, {Component, useState} from 'react'
import {
Text,
StyleSheet,
View,
FlatList,
SafeAreaView,
ScrollView,
Image,
TextInput,
} from 'react-native'
import data from '../../data'
const Flatlistexample = () => {
//main list state
let [list, setList] = useState(data)
//search state
const [search, setSearch] = useState('')
//filter state
const [updated, setUpdated] = useState(data)
//search filter
searchFilter = text => {
// onChangeText
if (text) {
const newData = list.filter(item => {
const listItem = `${item.name.toLowerCase()} ${item.company.toLowerCase()}`
return listItem.indexOf(text.toLowerCase()) > -1
})
setUpdated(newData)
}
//search function
renderHeader = () => {
return (
<View style={styles.seachContainer}>
<TextInput
style={styles.textInput}
placeholder={'Search...'}
value={search}
onChangeText={text => {
searchFilter(text)
setSearch(text)
}}></TextInput>
<Text
style={{
alignItems: 'flex-start',
color: 'black',
fontSize: 22,
}}>
{search}
</Text>
</View>
)
}
return (
<SafeAreaView
style={{
flex: 1,
}}>
<FlatList
//i'm showing filter state
data={updated}
renderItem={({item, index}) => {
return (
<ScrollView>
<SafeAreaView
style={[
styles.container,
{backgroundColor: index % 2 === 0 ? '#fafafa' : '#bbb'},
]}>
<Image style={styles.profile} source={{uri: item.picture}} />
<View style={styles.rightside}>
<Text style={styles.name}>{item.name}</Text>
<Text style={styles.company}>{item.company}</Text>
</View>
</SafeAreaView>
</ScrollView>
)
}}
keyExtractor={item => item._id}
//called search function
ListHeaderComponent={renderHeader()}
/>
</SafeAreaView>
)
}
export default Flatlistexample
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
borderBottomWidth: 1,
borderColor: 'gray',
},
profile: {
width: 50,
height: 50,
borderRadius: 25,
marginLeft: 10,
},
rightside: {
marginLeft: 20,
justifyContent: 'space-between',
marginVertical: 5,
},
name: {
fontSize: 22,
marginBottom: 10,
},
searchContainer: {
padding: 10,
borderWidth: 2,
borderColor: 'gray',
},
textInput: {
fontSize: 16,
backgroundColor: '#f9f9f9',
padding: 10,
},
})
/*
else if(text.length > uzunluk){
setList(data)
const newData = list.filter(item => {
const listItem = `${item.name.toLowerCase()} ${item.company.toLowerCase()}`
return listItem.indexOf(text.toLowerCase()) > -1;
})
setList(newData)
}else if(text.length<uzunluk){
setList(data)
const newData = list.filter(item => {
const listItem = `${item.name.toLowerCase()} ${item.company.toLowerCase()}`
return listItem.indexOf(text.toLowerCase()) > -1;
})
setList(newData)
}
*/

View dont refresh when add a new json object in array. REACT NATIVE

the program compiles perfect, but when I scan a product, it doesn't refresh in the view.
I have mounted a mysql xampp with all the products. when querying a barcode. I get in response the detail of the product, and, add the json response with parse object in a array.
the view refresh when click TouchableOpacity, later of scan a product.
import React, {Component, useState, useEffect} from 'react';
import {Dimensions,Image, View, Text,AsyncStorage, TouchableOpacity, Grid, StyleSheet, ScrollView,ToastAndroid} from 'react-native';
import { SearchBar, Card, Icon } from 'react-native-elements';
import { BarCodeScanner } from 'expo-barcode-scanner';
//import { NumberList } from './NumberList';
const {width, height} = Dimensions.get('window');
const urlApi = "http://192.168.1.24/rst/api/getProduct.php";
const numbers = [1,2,3,4,5,6];
class SaleScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
scan: false,
result: null,
ScanResult: false,
hasPermission: true,
setHasPermission: true,
productos: [],
jwt: null,
};
//this.componentDidMount();
}
async componentDidMount(){
let _jwt = await AsyncStorage.getItem('userToken');
this.setState({
jwt: _jwt
});
}
_searchProduct = async (data) => {
try {
let response = await fetch(urlApi,{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: 'Bearer '+this.state.jwt
},
body: JSON.stringify({
CodiBarra: data
})
});
let responseJson = await response.json();
//console.log(responseJson);
if (responseJson.codibarra === null) {
//console.log("retorna falso");
return false;
}
else
{
if(this.state.productos != null)
{
this.state.productos.push(responseJson[0]);
//this.setState({productos: this.state.productos.push(responseJson[0])})
//console.log(this.state.productos);
}
else
{
this.state.productos.push(responseJson[0]);
}
}
} catch (error) {
console.error(error);
}
};
render(){
const { scan, ScanResult, result, hasPermission, setHasPermission, productos } = this.state;
const activeBarcode = ()=> {
this.setState({
scan: true
})
}
const handleBarCodeScanned = async ({ type, data }) => {
//console.log('scanned data' + data);
this.setState({result: data, scan: false, ScanResult: false});
this._searchProduct(data);
};
if (hasPermission === null) {
return <Text>Requesting for camera permission</Text>;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View style= {{flex: 1}}>
{productos.length == 0 &&
<View style = {styles.button}>
<TouchableOpacity
onPress= {activeBarcode}
style={{
borderWidth:1,
borderColor:'rgba(0,0,0,0.2)',
alignItems:'center',
justifyContent:'center',
width:50,
height:50,
backgroundColor:'#fff',
borderRadius:50,
position: 'absolute',
marginTop: 10,
marginLeft: width - 100
}}
>
<Icon
type="font-awesome"
name="barcode"
/>
</TouchableOpacity>
</View>
}
{productos.length>0 &&
<View style={{flex:1}}>
<View style = {styles.button}>
<TouchableOpacity
onPress= {activeBarcode}
style={{
borderWidth:1,
borderColor:'rgba(0,0,0,0.2)',
alignItems:'center',
justifyContent:'center',
width:50,
height:50,
backgroundColor:'#fff',
borderRadius:50,
position: 'absolute',
marginTop: 10,
marginLeft: width - 100
}}
>
<Icon
type="font-awesome"
name="barcode"
/>
</TouchableOpacity>
</View>
<View style ={{flex:1,marginTop:20}}>
<ScrollView>
<NumberList products={this.state.productos} />
</ScrollView>
</View>
<View style ={{flex:1,marginTop:20}}>
<View style={{flexDirection:"row", height: 50, width: width, backgroundColor: "green", justifyContent: "center",}}>
<View style = {{ flexDirection:"column"}}>
<Text style = {{ fontSize: 40,color:"white"}}>{"TOTAL: "}</Text>
</View>
<View style={{justifyContent: "center", flexDirection:"row-reverse", paddingRight:20}}>
<Text style = {{ fontSize: 40,color:"white"}}>{result.precioventa}</Text>
</View>
</View>
</View>
</View>
}
{scan &&
<BarCodeScanner
onBarCodeScanned={handleBarCodeScanned}
style={StyleSheet.absoluteFillObject}
/>
}
</View>
);
}
}
function NumberList(props) {
console.log("NUMBERLIST")
console.log(props);
const products = props.products;
const listItems = products.map((product) =>
// Correct! Key should be specified inside the array.
<ListItem key={product.key} value={product} />
);
return (
<View>
{listItems}
</View>
);
}
function ListItem(props) {
// Correct! There is no need to specify the key here:
const u = props.value;
return (
<View>
{u &&
<Card>
<View style={{flexDirection:"row"}}>
<Icon
name = "monetization-on"
size = {40}
/>
<View style={{flex:1, flexDirection: "column", paddingTop: 10}}><Text>{u.descripcion}</Text></View>
<View style = {{flexDirection:"row-reverse", paddingTop: 10}}><Text>{u.precioventa}</Text></View>
</View>
</Card>
}
</View>);
}
const styles = StyleSheet.create({
container: {
backgroundColor: 'black'
},
containerHome:{
backgroundColor: 'white',
height: height,
width: width,
flexDirection: 'column'
},
cardSales:{
backgroundColor: 'white',
flex: 1,
padding: 15,
borderWidth: 1,
borderRadius: 10,
borderColor: '#ddd',
borderBottomWidth: 7,
//shadowColor: '#000',
shadowColor: "#191919",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.8,
shadowRadius: 2,
elevation: 1,
marginLeft: 5,
marginRight: 5,
marginTop: 20,
},
cardContent:{
flexDirection: 'row-reverse',
fontSize: 50
},
button:{
flexDirection: 'column',
marginTop: 20,
marginLeft: 20,
marginRight: 20,
},
contentActionFast:{
backgroundColor: 'white',
flexDirection: 'row',
alignItems:'center',
justifyContent: 'space-between',
flex:1
}
});
export default SaleScreen;
if anyone could help me I'd really appreciate it
Your component isn't re-rendering because in _searchProduct you're doing this.state.productos.push(responseJson[0]); to update the state object when you should be using setState(). Directly modifying the state, which you're doing now, won't trigger a re-render and could lead to other problems, which is why you should never do it and always use setState() (or a hook) to update state. This is mentioned in the docs here: https://reactjs.org/docs/state-and-lifecycle.html#do-not-modify-state-directly.
Instead try:
this.setState((prevState) => ({
productos: [...prevState.productos, responseJson[0]]
});

How to render a partial view on another view in react native

When I tried alert("Hi") in renderMoreView function, it actually works, but to display the View is the problem I am facing
export default class Home extends Component {
state = {
moreButton: false,
};
renderMoreView = () => {
return (
<View style={{flex: 1, height: 50, width: 50}}>
<Text>Hi</Text>
</View>
);
};
render () {
return (
<View>
.....
<TouchableOpacity
underlayColor="transparent"
onPress={() => this.setState ({moreButton: true})}
>
<Feather name="more-vertical" size={25} />
</TouchableOpacity>
...
{this.state.moreButton ? this.renderMoreView () : null}
</View>
);
}
}
This is what I am trying to do]
If I understand your question right, you could use Modal component. https://facebook.github.io/react-native/docs/modal
This can be done using modal. But if you want to do it more simply, install and use the module. react-native-awesome-alerts
$ npm i react-native-awesome-alerts --save
Example
import React from 'react';
import { StyleSheet, View, Text, TouchableOpacity } from 'react-native';
import AwesomeAlert from 'react-native-awesome-alerts';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = { showAlert: false };
};
showAlert = () => {
this.setState({
showAlert: true
});
};
hideAlert = () => {
this.setState({
showAlert: false
});
};
render() {
const {showAlert} = this.state;
return (
<View style={styles.container}>
<Text>I'm AwesomeAlert</Text>
<TouchableOpacity onPress={() => {
this.showAlert();
}}>
<View style={styles.button}>
<Text style={styles.text}>Try me!</Text>
</View>
</TouchableOpacity>
<AwesomeAlert
show={showAlert}
showProgress={false}
title="AwesomeAlert"
message="I have a message for you!"
closeOnTouchOutside={true}
closeOnHardwareBackPress={false}
showCancelButton={true}
showConfirmButton={true}
cancelText="No, cancel"
confirmText="Yes, delete it"
confirmButtonColor="#DD6B55"
onCancelPressed={() => {
this.hideAlert();
}}
onConfirmPressed={() => {
this.hideAlert();
}}
/>
</View>
);
};
};
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#fff',
},
button: {
margin: 10,
paddingHorizontal: 10,
paddingVertical: 7,
borderRadius: 5,
backgroundColor: "#AEDEF4",
},
text: {
color: '#fff',
fontSize: 15
}
});

Categories

Resources