null is not an object (evaluating 'teachers.length') - arrays

const [teachers, setTeachers] = useState([]);
const teachersList = async () => {
setLoading(true);
const storedValue = await AsyncStorage.getItem('#teachers_list');
if (!storedValue) {
setTeachers([]);
}
const list = JSON.parse(storedValue);
setTeachers(list);
setLoading(false);
}
useEffect(() => {
teachersList();
}, [isFocused])
return (
<SafeAreaView>
<ScrollView style={styles.mainContainer}>
{teachers.length == 0 ? (
<View style={styles.noData}>
<Text>Teacher List Empty</Text>
</View>
) : (
<>
{
teachers.map((teacher) => (
<View key={teacher.id} style={styles.productContainer} >
<View style={styles.productDetails}>
<Text> Name : {teacher.name}</Text>
<Text> Subject : {teacher.subject}</Text>
<Text> Email : {teacher.email}</Text>
</View>
<View style={styles.productButtonContainer}>
<TouchableOpacity style={styles.productActionEditButton} onPress={() => navigation.navigate("Edit", { teacher })}>
<Text> Edit </Text>
</TouchableOpacity>
<TouchableOpacity style={styles.productActionDelButton} onPress={() => deleteTeacher(teacher.id)}>
<Text> Delete </Text>
</TouchableOpacity>
</View>
</View>
))
}
</>
)}
</ScrollView>
</SafeAreaView>
)
The following code giving me an error. It was working when I was creating this application but now it's not working and showing me this error. I tried teachers && (code) but it is not working
null is not an object (evaluating 'teachers.length')

Edit: I just had to re-think the requirements of what you are doing
Instead of this:
teachers.length == 0 ? (
<View style={styles.noData}>
<Text>Teacher List Empty</Text>
</View>
)
try using this:
!teachers || teachers.length == 0 ? (
<View style={styles.noData}>
<Text>Teacher List Empty</Text>
</View>
)

Related

Adding Realtime firebase data with useState to a flatlist

I want to take this data and display it in a flatlist. I tried the way described below, but it wont show me anything in the flatlist. How would i be able to solve this problem?
Code for fetching data
useEffect(() => {
refComment.once('value').then(snapshot=>{
var li=[]
snapshot.forEach((child) => {
li.push({
// avatarIcon : child.val().avatarIcon,
// commentText : child.val().commentText,
// name : child.val().name,
// time : child.val().time,
// id : child.key
key:child.key,
comment:child.val()
}
)
}
)
setcommentData(li)
console.log(li);
})
} , []);
code for my flatlist
<Card>
<View style={styles.answerDetailsView}>
<View style={styles.allContentView}>
<Text style={styles.allContentText}>Tüm yorumlar</Text>
</View>
<Divider/>
<FlatList
data={commentData}
keyExtractor={(item)=>item.key}
renderItem={({item,index})=>{
return(
<View
index={index}
style={styles.contentView}>
<View style={styles.commentatorDetailView}>
<View style={styles.commentatorAvatarView}>
<Avatar.Icon
size={30}
icon={item.avatarIcon}
/>
</View>
<View style={styles.commentatorNameAndTimeView}>
<Text>{item.name}</Text>
<Text>{item.time}</Text>
</View>
<View style={styles.commentatorLikeView}>
<TouchableOpacity>
<Icon
name='thumbs-up'
/>
</TouchableOpacity>
</View>
</View>
<View style={styles.contentTextView}>
<Text style={styles.contentText}>
{item.commentText}
</Text>
</View>
</View>
)
}}
/>
</View>
</Card>
And RealTime firebase screen
enter image description here
my mobile screenshot
enter image description here
Try to refactor logic to fetch comments as below:
function getComments() {
const commentsRef = firebase.database().ref("comments");
commentsRef.on("value", (snapshot) => {
if (snapshot.val()) {
const data = snapshot.val();
const comments = Object.values(data) || [];
setcommentData(comments);
}
});
}
useEffect(() => {
getComments();
}, []);

Navigation from menu item

I'm trying to get a menu item to navigate to another page but for some reason it wont let me do it. I'm a little confused as to how you go about it and any help is welcome!
Import here:
import { NavigationScreenProp } from "react-navigation";
Here is more code:
interface NotificationDropdownProps {
navigation: NavigationScreenProp<any, any>;
}
Here is where function is called:
function renderNotification(notification: INotification) {
return (
<MenuOption
onSelect={() => {
if (notification.type == INotificationType.SYSTEM) {
this.testFunction();
}
}}
>
<View style={[styles.notificationContainer]}>
<View style={styles.iconArea}>
<View style={[styles.iconCircle]}>
<Icon
name={this.getIconType(notification.type)}
color={this.notificationColor(notification.type)}
size={26}
/>
</View>
</View>
<View>
<Text>{notification.text}</Text>
<Text>
{this.getDate(new Date(notification.dateCreated))}
</Text>
</View>
</View>
</MenuOption>
);
}
Test Function:
testFunction(){
this.props.navigation.navigate('NextPage')
};
Error:
undefined is not an object(evaluating'_this2.props.naviagtion.navigate)
Where the function is called:
<View>
<Text>
Notifications
</Text>
{this.props.notifications.length > 0 ? (
<FlatList
contentContainerStyle={{ borderRadius: 10 }}
data={this.props.notifications.slice(0, 5)}
renderItem={({ item }) => this.renderNotification(item)}
keyExtractor={this.keyExtractor}
/>
) : (
<Text>No Notifications!</Text>
)}
</View>;
try with an arrow function to avoid using the context of the function.
testFunction = () => {
this.props.navigation.navigate('NextPage')
};

TypeError : undefined is not a function(near '...props.items.map...')

Getting Error when I am trying to call values from my CartItem Object.
TypeError : undefined is not a function(near '...props.items.map...')
Any help will be greatly appreciated.
const OrderItem = (props) => {
const [showDetails, setShowDetails] = useState(false);
return (
<View style={styles.orderItem}>
<View style={styles.summary}>
<TouchableOpacity
style={styles.detailsbtn}
onPress={() => {
setShowDetails((prevState) => !prevState);
}}>
<Text style={styles.id}>
{showDetails ? 'Hide Details' : 'Details'}
</Text>
</TouchableOpacity>
</View>
{showDetails && (
<View style={styles.detailItems}>
{props.items.map((cartItem) => (
<CartItem
key={cartItem.productId}
quantity={cartItem.quantity}
amount={cartItem.sum}
title={cartItem.productTitle}
/>
))}
</View>
)}
</View>
);
};

React Native class component accordion into functional component

The following code displays an accordion but I need to make use of useContext which I understand only works with functional components and I'm having a hard time understand how to convert it into a functional component.
class AnnualFeeScreen extends Component {
state = {
activeSections: [],
};
_renderHeader(section, index, isActive) {
let meanValStatus = '#39D0B5';
if (section.meanDiffVal >= 1.05) {
meanValStatus = '#FCD561';
} else if (section.meanDiffVal < 0.95) {
meanValStatus = '#bbb';
}
return (
<View style={styles.flexRow}>
<View style={{flex:2}}>
<Text style={styles.h6}>{!isActive ? '+' : '-'} {section.title}</Text>
</View>
<View style={styles.flex}>
<Text style={[styles.h6, {textAlign: 'right'}]}>{Math.round((section.titleValue) / 12, 0)} kr/mån</Text>
</View>
<View style={[styles.circleStatus, {backgroundColor: meanValStatus}]}></View>
</View>
);
};
_renderContent = section => {
return (
<View>
{section.content.map((item, key) =>
<View style={styles.accordionContent} key={key}>
<View style={styles.flexRow}>
<View style={{flex: 2}}>
<Text style={[styles.p, {fontWeight: 'normal'}]}>{item.title}</Text>
</View>
<View style={styles.flex}>
<Text style={[styles.p, {fontWeight: 'normal', textAlign: 'right'}]}>{Math.round((item.value * aptPercentage) / 12, 0)} kr/mån</Text>
</View>
</View>
</View>
)}
</View>
);
};
_updateSections = activeSections => {
this.setState({ activeSections });
};
render () {
return (
<ScrollView style={styles.backgroundPrimary} showsVerticalScrollIndicator='false'>
<View style={styles.backgroundSecondary}>
<View style={styles.container}>
<Accordion
sections={brfCostRows}
activeSections={this.state.activeSections}
renderHeader={this._renderHeader}
renderContent={this._renderContent}
onChange={this._updateSections}
sectionContainerStyle={styles.accordion}
underlayColor='transparent'
/>
</View>
</View>
</ScrollView>
);
};
};
To fetch data with axios I use the following in other screens but it's not working with the class component:
const { state, fetchUser } = useContext(UserContext);
And in the view:
<NavigationEvents onWillFocus={fetchUser} />
I've tried to remove the render part change the first part to the following but it's complaining about the first function _renderHeader (Unexpected token):
const AnnualFeeScreen = () => {
First of all while converting, class component to functional component with hooks, you must note that, there won't be a this variable inside functional component. Secondly the state inside a functional component would need to be implemented using useState hook
const AnnualFeeScreen () => {
const [activeSections, setActiveSections] = useState([]);
const _renderHeader(section, index, isActive) {
let meanValStatus = '#39D0B5';
if (section.meanDiffVal >= 1.05) {
meanValStatus = '#FCD561';
} else if (section.meanDiffVal < 0.95) {
meanValStatus = '#bbb';
}
return (
<View style={styles.flexRow}>
<View style={{flex:2}}>
<Text style={styles.h6}>{!isActive ? '+' : '-'} {section.title}</Text>
</View>
<View style={styles.flex}>
<Text style={[styles.h6, {textAlign: 'right'}]}>{Math.round((section.titleValue) / 12, 0)} kr/mån</Text>
</View>
<View style={[styles.circleStatus, {backgroundColor: meanValStatus}]}></View>
</View>
);
};
const _renderContent = section => {
return (
<View>
{section.content.map((item, key) =>
<View style={styles.accordionContent} key={key}>
<View style={styles.flexRow}>
<View style={{flex: 2}}>
<Text style={[styles.p, {fontWeight: 'normal'}]}>{item.title}</Text>
</View>
<View style={styles.flex}>
<Text style={[styles.p, {fontWeight: 'normal', textAlign: 'right'}]}>{Math.round((item.value * aptPercentage) / 12, 0)} kr/mån</Text>
</View>
</View>
</View>
)}
</View>
);
};
const _updateSections = activeSections => {
setActiveSections(activeSections);
};
return (
<ScrollView style={styles.backgroundPrimary} showsVerticalScrollIndicator='false'>
<View style={styles.backgroundSecondary}>
<View style={styles.container}>
<Accordion
sections={brfCostRows}
activeSections={activeSections}
renderHeader={_renderHeader}
renderContent={_renderContent}
onChange={_updateSections}
sectionContainerStyle={styles.accordion}
underlayColor='transparent'
/>
</View>
</View>
</ScrollView>
);
};

How to pass Parent Flatlist's Index value to Child Flatlist's onPress function?

How to pass parent Flatlist's index value to child Flatlist's function so I can use it in function and change value by setState.
So how to pass parent Flatlist's index value to child Flatlist's function so I can use it in function and change value by setState.
It starts with a list that built-in state
constructor(props) {
super(props);
this.state = {
list: [
{
question: 'il veicolo ha la gomma forata?',
answers: [
{
radioButtonValue: false,
text: strings.CONFIRMVIEW_yes,
},
{
radioButtonValue: true,
text: strings.CONFIRMVIEW_no,
},
],
},
]
}
}
checkBoxSelection = (item, index) => {
// if (item.radioButtonValue == index) {
// this.list.answers[index].radioButtonValue = true
// }
console.log(this.state.list[0].answers[index].radioButtonValue)
}
_renderItem = ({ item, index }) => {
return (
<View style={styles.cellView}>
<Text style={styles.questionText}>
{item.question.toUpperCase()}
</Text>
<FlatList
data={item.answers}
horizontal={true}
showsHorizontalScrollIndicator={true}
scrollEnabled={true}
bounces={false}
renderItem={this._renderItemOptions}
/>
{/* <View style={styles.yesNoRadioButtonView}>
<View style={styles.yesChekboxView}>
<TouchableOpacity onPress={ () => {console.log("TEST1"); this.checkBoxSelection()} }>
<Image source={(item.answers == index) ? AppImages.radioOn : AppImages.radioOff} style={styles.radioButton} />
</TouchableOpacity>
<Text style={styles.yesNoText}>
{strings.CONFIRMVIEW_yes}
</Text>
</View>
<View style={styles.noRadioButtonView}>
<TouchableOpacity onPress={() => { this.checkBoxSelection.bind(this) }}>
<Image source={(item.answers == 0) ? AppImages.radioOn : AppImages.radioOff} style={styles.radioButton} />
</TouchableOpacity>
<Text style={styles.yesNoText}>
{strings.CONFIRMVIEW_no}
</Text>
</View>
</View> */}
</View>
)
}
_renderItemOptions = ({ item, index }) => {
return (
<View>
<View style={styles.yesNoRadioButtonView}>
<TouchableOpacity onPress={() => { this.checkBoxSelection(item, index) }}>
<View style={styles.yesChekboxView}>
<Image
source={item.radioButtonValue ? AppImages.radioOn : AppImages.radioOff}
style={styles.radioButton}
/>
<Text style={styles.yesNoText}>
{item.text}
</Text>
</View>
</TouchableOpacity>
</View>
</View>
)
}
render() {
return (
<Container>
<Content style={styles.container}>
<FlatList
data={this.state.list}
showsVerticalScrollIndicator={false}
scrollEnabled={false}
bounces={false}
renderItem={this._renderItem}
/>
</Content>
<SafeAreaView>
<TouchableOpacity
style={[LayoutStyle.appBtn1]}
>
<Text style={[LayoutStyle.appBtnText1]}>
{strings.DAMAGE_SURVEY_comeOn.toUpperCase()}
</Text>
</TouchableOpacity>
</SafeAreaView>
</Container>
)
}
In Parent Flatlist's renderItem function
replace
renderItem = { () => {this.renderItemOptions(item, index)}}
with
renderItem={(childData) => this._renderItemOptions(childData, index)}
and then in child Flatlist's renderItemOption function need to get parentIndex with another name.
_renderItemOptions = ({ item, index }, parentIndex) => {
console.log("hello")
return (
<View>
<View style={styles.yesNoRadioButtonView}>
<TouchableOpacity onPress={() => { this.checkBoxSelection(item, index, parentIndex) }}>
<View style={styles.yesChekboxView}>
<Image
source={item.radioButtonValue ? AppImages.radioOn : AppImages.radioOff}
style={styles.radioButton}
/>
<Text style={styles.yesNoText}>
{item.text}
</Text>
</View>
</TouchableOpacity>
</View>
</View>
)
}
Try updating your renderItem prop in your FlatList to explicitly pass the index
renderItem={({item, index}) => this._renderItemOptions(item, index)}

Resources