TouchableOpacity onPress() function doesn't works - reactjs

I tried to create a DraggableList with some checkboxes, the problem is my component doesn't trigger the "onPress" while the "onLongPress" method working fine...
I tried to remove the "onLongPress" method, but still the same.
Here is my whole component :
class Menus extends React.Component {
state = {
menusItems: global.conf.Menus.map((d, index) => ({
id: d.id,
key: `item-${d.id}`,
label: d.label,
path: d.path,
value: d.value,
backgroundColor: `rgb(${Math.floor(Math.random() * 255)}, ${index *
5}, ${132})`,
})),
};
renderItem = ({item, index, drag, isActive}) => {
return (
<TouchableOpacity
style={{
backgroundColor: isActive ? 'blue' : item.backgroundColor,
alignItems: 'center',
justifyContent: 'center',
}}
onLongPress={drag}
onPress={() => console.log('puff')}>
<Checkbox
status={item.value ? 'checked' : 'unchecked'}
key={item.id}
title={item.label}
/>
</TouchableOpacity>
);
};
return (
<View style={{flex: 1}}>
<DraggableFlatList
data={this.state.menusItems}
renderItem={this.renderItem}
keyExtractor={(item, index) => `draggable-item-${item.key}`}
onDragEnd={({data}) => this.setMenus(data)}
/>
</View>
);
}
}
export default Menus;
I don't know what is wrong ....

Related

React Native Update Parent Array from Child Component

I am having trouble updating an array that is passed as a prop into my child component. I have searched around but haven't found an answer that can directly solve my problem. My code is as follows:
App.js
import React, { Component } from 'react';
import { StyleSheet, Text, View, SafeAreaView } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import AddMedication from "./src/AddMedication";
import MedicationList from './src/MedicationList';
const Stack = createNativeStackNavigator();
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
medications: [],
}
this.addMedication = this.addMedication.bind(this);
}
addMedication = (name, dosage, measurement, timesDaily) => {
console.log("Medication added.")
var newItem = {name: name, dosage: dosage, measurement: measurement, timesDaily: timesDaily}
this.setState({
medications: [...this.state.medications, newItem]
})
}
render() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Medication List">
{(props) => <MedicationList {...props} medications={this.state.medications} />}
</Stack.Screen>
<Stack.Screen name="Add New Medication">
{(props) => <AddMedication {...props} addMedication={this.addMedication} />}
</Stack.Screen>
</Stack.Navigator>
</NavigationContainer>
);
}
}
This is the home screen where I am trying to display the array but nothing shows up
MedicationList.js
class MedicationList extends Component {
constructor(props) {
super(props);
this.state = {
tableHead: ['Name', 'Dosage', 'Times Daily', 'Prescriber', 'For Diagnosis'],
}
}
medication = ({ item }) => {
<View style={{ flexDirection: 'row' }}>
<View style={{ width: 50, backgroundColor: 'lightyellow'}}>
<Text style={{ fontSize: 16, fontWeight: 'bold', textAlign: 'center'}}>{item.name}</Text>
</View>
<View style={{ width: 400, backgroundColor: 'lightpink'}}>
<Text style={{ fontSize: 16, fontWeight: 'bold' , textAlign: 'center'}}>{item.dosage}{item.selectedMeasurement}</Text>
</View>
<View style={{ width: 400, backgroundColor: 'lavender'}}>
<Text style={{ fontSize: 16, fontWeight: 'bold' , textAlign: 'center'}}>{item.timesDaiy}</Text>
</View>
</View>
}
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', marginTop: '10%'}}>
<Button
title="+ Add New Medication"
onPress={() => {
/* 1. Navigate to the Details route with params */
this.props.navigation.navigate('Add New Medication', {
medications: this.props.medications,
});
}}
/>
<FlatList
data={this.props.medications}
renderItem={this.medication}
/>
</View>
);
}
}
This is where I click the add button to update the medications array
AddMedication.js
class AddMedication extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
dosage: 0,
selectedMeasurement: "mg",
timesDaily: '',
prescriber: '',
forDiagnoses: '',
instructions: '',
validity: false,
};
}
setName = (name) => {
let isValid = this.isFormValid();
this.setState({ name: name, validity: isValid });
}
setDosage = (dosage) => {
let isValid = this.isFormValid();
this.setState({ dosage: dosage, validity: isValid });
}
setMeasurement = (measurement) => {
this.setState({ selectedMeasurement: measurement });
}
setTimesDaily = (timesDaily) => {
let isValid = this.isFormValid();
this.setState({ timesDaily: timesDaily, validity: isValid });
}
setPrescriber = (prescriber) => {
this.setState({ prescriber: prescriber });
}
setDiagnoses = (diagnoses) => {
this.setState({ forDiagnoses: diagnoses });
}
setInstructions = (instructions) => {
this.setState({ instructions: instructions });
}
isFormValid = () => {
return (this.state.name !== '' && (this.state.dosage !== '' && this.state.dosage > 0)
&& (this.state.timesDaily !== '' && this.state.timesDaily > 0));
}
render() {
return (
<View style={styles.container}>
<Text style={{color: 'red', marginBottom: 5, marginLeft: -125}}>* denotes required field</Text>
<View style={{flexDirection: 'row'}}>
<Text style={styles.required}>*</Text>
<TextInput
style={styles.inputText}
onChangeText={(name) => this.setName(name)}
placeholder="Medication Name"
value={this.state.name}
/>
</View>
<View style={{flexDirection: 'row'}}>
<Text style={styles.required}>*</Text>
<TextInput
style={styles.inputText}
onChangeText={(dosage) => this.setDosage(dosage)}
placeholder="Dosage"
value={this.state.dosage}
/>
</View>
<View style={styles.dosageContainer}>
<Text style={{flex: 1, marginTop: 100, marginLeft: 30}}>
Select Measurement:
</Text>
<Picker
style={styles.picker}
selectedValue={this.state.selectedMeasurement}
onValueChange={(itemValue, itemIndex) =>
this.setMeasurement(itemValue)
}>
<Picker.Item label="mg" value="mg" />
<Picker.Item label="g" value="g" />
<Picker.Item label="ml" value="ml" />
</Picker>
</View>
<View style={{flexDirection: 'row'}}>
<Text style={styles.required}>*</Text>
<TextInput
style={styles.inputText}
onChangeText={(timesDaily) => this.setTimesDaily(timesDaily)}
placeholder="Times daily"
value={this.state.timesDaily}
/>
</View>
<TextInput
style={styles.inputText}
onChangeText={(prescriber) => this.setPrescriber(prescriber)}
placeholder="Prescriber"
value={this.state.prescriber}
/>
<TextInput
style={styles.inputText}
onChangeText={(diagnoses) => this.setDiagnoses(diagnoses)}
placeholder="For diagnoses"
value={this.state.forDiagnoses}
/>
<TextInput
style={styles.inputText}
onChangeText={(instructions) => this.setInstructions(instructions)}
placeholder="Instructions"
value={this.state.instructions}
/>
<TouchableOpacity
style={this.isFormValid() ? styles.validButton : styles.invalidButton}
disabled={!Boolean(this.state.name && this.state.dosage && this.state.timesDaily)}
onPress={() => {
this.props.navigation.goBack()
this.props.addMedication(this.state.name, this.state.dosage,
this.state.selectedMeasurement, this.state.timesDaily)
}}
>
<Text style={{color: 'white'}}>Add Medication</Text>
</TouchableOpacity>
</View>
)
}
}
You can pass the state value but I think you cannot pass the addMedication method just like this.
Could you please try passing an arrow function that uses the setState method?
For example:
<Stack.Screen name="Add New Medication">
{(props) => <AddMedication {...props} addMedication={(name, dosage, measurement, timesDaily)=> {this.addMedication(name, dosage, measurement, timesDaily)}} />}
</Stack.Screen>

Check visibility of item at the screen

I have FlastList with data. I need to check if item from the Flastlist is seen. So if i do not see data at my screen i do not have to do anything, but if i see i have to console.log data info. And when i am scrolling i have to console.log data that is visibile. I am trying to use onViewableItemsChanged with viewabilityConfig, but when i console.log data, it returns all data from FlastList but not data that is seen. Help me please.
I will be very thankfull!
_onViewableItemsChanged = ({ viewableItems, changed }) => {
console.log("Visible items are", viewableItems.map(item => item.item.text));
};
_viewabilityConfig = {
viewAreaCoveragePercentThreshold: 100
};
//....
<FlatList
data={this.state.postData}
initialNumToRender={0}
ItemSeparatorComponent = {this.FlatListItemSeparator}
renderItem={({item}) => {
return (
<View style={{paddingTop: 15}}
ref={ (divElement) => { this.divElement = divElement } }
>
// data
)}
}
onViewableItemsChanged={this._onViewableItemsChanged}
viewabilityConfig={this._viewabilityConfig}
keyExtractor={item => item.id}
/>
In your comment you specified that the FlatList is inside a view and scrollview. I tried to reproduce it this way:
<View style={styles.container}>
<ScrollView style={styles.scrollView}>
<FlatList
data={DATA}
initialNumToRender={0}
renderItem={renderItem}
onViewableItemsChanged={onViewableItemsChanged}
viewabilityConfig={viewabilityConfig}
keyExtractor={item => item.id}
/>
</ScrollView>
</View>
And indeed, console.log shows all data in this case. When I removed ScrollView so that the FlatList is inside the View element (with flex:1) then it works correctly - console.log shows only visible elements. My code:
const DATA = [
{
id: '1',
title: 'First Item',
},
// ... more elements
];
const Item = ({ title }) => (
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
);
const renderItem = ({item}) => {
return (
<View style={{paddingTop: 15}}
ref={ (divElement) => { this.divElement = divElement } }
>
<Item title={item.title} />
</View>
)
}
const viewabilityConfig = {
viewAreaCoveragePercentThreshold: 100
};
const onViewableItemsChanged = ({ viewableItems, changed }) => {
console.log("Visible items are", viewableItems.map(item => item.item.title));
};
export default function App() {
return (
<View style={styles.container}>
<FlatList
data={DATA}
initialNumToRender={0}
renderItem={renderItem}
onViewableItemsChanged={onViewableItemsChanged}
viewabilityConfig={viewabilityConfig}
keyExtractor={item => item.id}
/>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
item: {
backgroundColor: '#f9c2ff',
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 32,
},
});

TypeError: Can't read property 'map of undefined in React Native

I am doing react native project. I have array of data and in render method I am trying to looping it, Its like some custom tabbar. But, After loaded, I am trying to switching from one tab to another tab, Its throwing error and crashing like
TypeError: Can't read property 'map of undefined in React Native .
My code is
dashboard.js
constructor(props) {
super(props);
this.state = {
selectedIndex:0,
tabList:[
{tabName: ‘Telugu’, tabActiveImage:TeluguActiveImg, tabInactiveImage: TeluguInActiveImg, tabActiveText:'black', tabInactiveText: 'gray'},
{tabName: ‘Tamil’, tabActiveImage:TeluguActiveImg, tabInactiveImage: TeluguActiveImg, tabActiveText:'black', tabInactiveText: 'gray'},
{tabName: ’Hindi’, tabActiveImage: HindiActiveImg, tabInactiveImage: HindiInActiveImg, tabActiveText:'black', tabInactiveText: 'gray'},
{tabName: ‘English’, tabActiveImage: EnglishActiveImg, tabInactiveImage: EnglishInActiveImg, tabActiveText:'black', tabInactiveText: 'gray'},
]
}
}
OnTabItemHandler = (index) => {
this.setState({selectedIndex:index})
console.log('selected index is',index)
}
render(item) {
const {tabList} = this.state;
return (
<View>Some static data loading </View>
<View style = {styles.tabContainer}>
{
//loop throught the state
this.state.tabList.map((item,index)=>{
return(
//the style just to make it beautiful and easy to debug
<View style ={styles.tabInnerContainer}>
<TouchableOpacity style={styles.tabIcons}
//this onpress to handle of active selected tab
onPress={()=>this.OnTabItemHandler(index)}
>
<Image
//here's the magic show off
source={this.state.selectedIndex=index?item.tabActiveImage:item.tabInactiveImage}
style={styles.tabItemsImages}
/>
<Text style={styles.tabItemTextBlackColor}>{item.tabName}</Text>
</TouchableOpacity>
</View>
)
})
}
</View>
{this.renderBottomContent(item)}
</View>
);
}
}
and bottom view is
based on tab, I am changing the bottom view
renderBottomContent = (item) => {
this.state = { dataArray: getListData()}
switch(selectedTab) {
case "Telugu":
return <View style = {styles.flatListContainer}>
//show flat list data
}
ItemSeparatorComponent = {() => (
<View style={{height:15, backgroundColor:'blue'}/>
)}
/>
</View >
case "Tamil":
return <View style = {styles.bottomStaicScreensForTabs}>
<Text>
Tamil feature will come
</Text>
</View>
case "Hindi":
return <View style = {styles.bottomStaicScreensForTabs}>
<Text>
Hindi feature will come
</Text>
</View>
default:
return <View><Text></Text></View>
}
}
And also tab text colour not changing, always coming as black. Can
anyone help me, where I am doing wrong.
To better understand the problem I've created a snack. I'll post the code here in case it will no longer be available.
Note: it's not styled properly and images are not dynamic as you intend, but it can reproduce the question pretty well.
constructor(props) {
super(props);
this.state = {
selectedIndex: 0,
tabList: [
{
tabName: 'Telugu',
tabActiveImage: '',
tabInactiveImage: '',
tabActiveText: 'black',
tabInactiveText: 'gray',
},
{
tabName: 'Tamil',
tabActiveImage: '',
tabInactiveImage: '',
tabActiveText: 'black',
tabInactiveText: 'gray',
},
{
tabName: 'Hindi',
tabActiveImage: '',
tabInactiveImage: '',
tabActiveText: 'black',
tabInactiveText: 'gray',
},
{
tabName: 'English',
tabActiveImage: '',
tabInactiveImage: '',
tabActiveText: 'black',
tabInactiveText: 'gray',
},
],
};
}
onTabItemHandler = index => {
this.setState({ selectedIndex: index });
};
renderBottomContent = () => {
const { selectedIndex, tabList } = this.state;
const itemSelected = tabList[selectedIndex];
switch (itemSelected.tabName) {
case 'Telugu':
return (
<View style={{backgroundColor: 'yellow'}}>
<Text>Telugu feature will come</Text>
</View>
);
case 'Tamil':
return (
<View style={{backgroundColor: 'green'}}>
<Text>Tamil feature will come</Text>
</View>
);
case 'Hindi':
return (
<View style={{backgroundColor: 'cyan'}}>
<Text>Hindi feature will come</Text>
</View>
);
default:
return (
<View>
<Text>No content</Text>
</View>
);
}
};
render() {
const { tabList, selectedIndex } = this.state;
return (
<View style={styles.container}>
<Text>Some static data loading </Text>
<View style={styles.tabContainer}>
{//loop throught the state
tabList.map((item, index) => {
return (
//the style just to make it beautiful and easy to debug
<View style={styles.tabInnerContainer}>
<TouchableOpacity
style={styles.tabIcons}
//this onpress to handle of active selected tab
onPress={() => this.onTabItemHandler(index)}>
<Image
//here's the magic show off
source={
selectedIndex === index
? require('./assets/snack-icon.png')
: undefined
}
style={{ height: 30, width: 30 }}
/>
<Text
style={{
color:
selectedIndex === index
? item.tabActiveText
: item.tabInactiveText,
}}>
{item.tabName}
</Text>
</TouchableOpacity>
</View>
);
})}
</View>
{this.renderBottomContent()}
</View>
);
}
I'm still here for any clarification or improvement.
Update
Adding style like:
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'flex-start',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
tabContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
},
});

How to stop React-Native FlatList Interfering with other components

I have a simple React-Native app that uses FlatList with Redux. The problem is that when the list becomes long and reaches the bottom of the screen where the input elements exists it disrupts these input elements even though they are in another component and container. I've tried a million fixes for this, but nothing seems to work.
How can I do something like only have FlatList occupy 2/3rds of the screen?
This is a screenshot of the issue (when the items reach the input boxes it results in the input boxes shrinking and being disrupted):
This is the app file that contains all my components:
export default class App extends Component {
render() {
return (
<Provider store={createStore(reducers)}>
<View style={{ flex: 1 }}>
<ItemsList />
<AddItem />
</View>
</Provider>
);
}
}
This is the component that uses FlatList:
class ItemsList extends Component {
render() {
return (
<List>
<FlatList
data={this.props.items}
renderItem={({ item }) => (
<ListItem
name={item.item} id={item.id}
/>
)}
keyExtractor={item => item.id.toString() }
/>
</List>
);
}
}
const mapStateToProps = state => {
return { items: state.items };
};
export default connect(mapStateToProps)(ItemsList);
The code for addItem is:
class AddItem extends Component {
state = {
item: "",
quantity: ""
}
onButtonPress() {
this.props.addItem(this.state)
this.setState({
item: "",
quantity: 0
})
}
render() {
const { input, container, add, addText } = styles;
return (
<View style={container}>
<TextInput placeholder="add item"
placeholderTextColor="rgba(0, 0, 0, 0.5)"
style={input}
onChangeText={item => this.setState({ item })}
value={this.state.item}
/>
<TextInput placeholder="add item"
placeholderTextColor="rgba(0, 0, 0, 0.5)"
style={input}
onChangeText={quantity => this.setState({ quantity })}
/>
<TouchableOpacity style={add} onPress={this.onButtonPress.bind(this)}>
<Text style={addText}>Add Item</Text>
</TouchableOpacity>
</View>
);
}
}
export default connect(null, {addItem})(AddItem);
const styles = {
input: {
backgroundColor: 'rgb(208, 240, 238)',
paddingVertical: 15,
paddingHorizontal: 10,
marginBottom: 5
},
add: {
backgroundColor: 'black',
paddingVertical: 15,
},
addText: {
textAlign: 'center',
color: 'white'
},
container: {
padding: 20,
flex: 1,
justifyContent: 'flex-end'
}
};
First of all, remove <List> from your ItemsList since you already use FlatList. Then, for your FlatList to take up 2/3 of the screen height do this:
class ItemsList extends Component {
render() {
return (
<View style={{ flex: 2 }}>
<FlatList
data={this.props.items}
renderItem={({ item }) => (
<ListItem
name={item.item} id={item.id}
/>
)}
keyExtractor={item => item.id.toString() }
/>
</View>
);
}
}
const mapStateToProps = state => {
return { items: state.items };
};
export default connect(mapStateToProps)(ItemsList);

Change background of list item

How can I change the background color of multiple list items when they are selected? I am using react-native-accordian and react-native-collapsible and using flat list within content.
_renderContent(section, i, isActive)
{
//console.log("MY DATA---",section.time_slots);
return (
<List
style={inStyles.body}
containerStyle={{ borderTopWidth: 0, borderBottomWidth: 0 }}>
<FlatList
data={section.time_slots}
renderItem={
({ item,index }) =>
(
<ListItem
onPress={() => this.selectSlot(item,section.date,index)}
style = {[inStyles.list , {marginLeft : 15}, {marginRight : 5},
{backgroundColor: (this.state.selectedItem[index]) ? 'green' : 'red'}]}
title={`${item}`}
containerStyle={{ borderBottomWidth: 0 }}
/>
)
}
keyExtractor={item => section.date+item}
ItemSeparatorComponent={this.renderSeparator}
ListFooterComponent={this.renderFooter}
/>
</List>
);
}
I just want to change the style of a list item dynamically using TouchableOpacity. But unable to do so.
You should change your code as below, your class would be like this:
contructor (props) {
super(props)
let selectedItemTemp = []
for(let i=0; i<section.time_slots.length; i++) { //section.time_slots is your FlatList data
selectedItemTemp.push(false)
}
this.state = {selectedItem: selectedItemTemp}
}
selectSlot = (item, section.date, index) => {
let {selectedItem} = this.state
selectedItem[index] = !selectedItem[index]
this.setState({selectedItem})
... // your other codes
}
render() {
return (
...
<FlatList
data={section.time_slots}
renderItem={
({ item, index }) => (
<TouchableOpacity
onPress={() => this.selectSlot(item,section.date, index)}>
<ListItem style = {[inStyles.list , {marginLeft : 15}, {marginRight : 5}, {backgroundColor: (this.state.selectedItem[index]) ? 'green' : 'white'}]}
title={`${item}`}
containerStyle={{ borderBottomWidth: 0 }}
/>
</TouchableOpacity>
)
} {item => section.date+item}
ItemSeparatorComponeultiple Selectiont={this.renderSeparator}
ListFooterComponent={this.renderFooter}
/>
...
);
}

Resources