I have problem with input text when I try to change it return to previous value was working fine out side map func. but inside it refuse to change it value. I think it re render itself on change text.
so how do I change text and save name
userdata.map((l, i) => (
<Input label='First Name' value={l.name}
onChangeText={setname} />
<Button title="Modify" onPress={() =>
modifyDetails(
name,
)
} />
))
Edit: Based on Mohammad code I have done this
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
Alert.alert("Modal has been closed.");
}}
>
<ScrollView>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<TouchableHighlight
onPress={() => {
setModalVisible(!modalVisible);
}}
>
<Text style={styles.textStyleClose}>X</Text>
</TouchableHighlight>
<UserDataWithCallback/> // inputs called here
</View>
</View>
</ScrollView>
</Modal>
But now renders empty inputs. Any solution.
useCallback will solve your problem.\
const userDataWithCallback = React.useCallback((l, i) => {
return (
<> // maybe a key prop is needed too
<Input
label='First Name'
value={l.name}
onChangeText={setname} />
<Button
title="Modify"
onPress={() => modifyDetails(name)} />
</>
)
}, [])
userdata.map((l, i) => (
userDataWithCallback(l, i)
))
Related
I have a form where I am using KeyboardAvoidingView and ScrollView so that when a user clicks on an input field the screen will scroll to that particular field
Within my form I have an input field that is searchable and I am using a FlatList to display the results for the user to choose from. Currently I am getting the error:
VirtualizedLists should never be nested inside plain ScrollViews
I've looked at many posts around this but am yet to find a solution (unless I've missed something):
1 - How to put FlatList inside of the ScrollView in React-native?
2 - FlatList inside ScrollView doesn't scroll
3 - How to make a FlatList scrollable inside of a ScrollView in react native?
This is what I have so far:
export const SignUpMember = ({navigation}) => {
const renderHeader = formikProps => {
return (
<>
<FormField
keyboardType={'default'}
fieldName={'firstName'}
label={'First Name'}
/>
<FormField
keyboardType={'default'}
fieldName={'lastName'}
label={'Last Name'}
/>
<FormField
onChangeText={text => {
formikProps.values.clubName = text;
searchItems(text);
}}
value={formikProps.values.clubName}
keyboardType={'default'}
fieldName={'clubName'}
label={'Club Name'}
placeholder={'Search Club By Name...'}
/>
</>
);
};
const renderFooter = formikProps => {
return (
<>
<FormField
keyboardType={'phone-pad'}
fieldName={'telephone'}
label={'Telephone'}
/>
<FormField
keyboardType={'email-address'}
fieldName={'email'}
label={'Email'}
/>
<FormField
keyboardType="default"
secureTextEntry={true}
fieldName={'password'}
label={'Password'}
type={'password'}
/>
<FormField
keyboardType="default"
secureTextEntry={true}
fieldName={'passwordConfirmation'}
label={'Confirm Password'}
type={'password'}
/>
<Button
mt="2"
bg="brand.blue"
type="submit"
onPress={formikProps.handleSubmit}>
Sign Up
</Button>
</>
);
};
return (
<KeyboardAvoidingView
keyboardVerticalOffset={headerHeight}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
<ScrollView
_contentContainerStyle={styles.container}
nestedScrollEnabled={true}>
<Box p="1" py="8" w="90%" maxW="290">
<VStack space={3} mt="5">
<Formik
initialValues={initialFormValues}
onSubmit={values => handleFormSubmit(values)}
validationSchema={userValidationSchema}>
{formikProps => (
<View>
<FlatList
nestedScrollEnabled={true}
data={flatListData}
renderItem={({item}) => (
<Pressable
onPress={() => {
formikProps.values.clubName = item.name;
setFlatListData([]);
}}>
<Text style={styles.flatList}>{item.name}</Text>
</Pressable>
)}
keyExtractor={item => item.name}
ListHeaderComponent={renderHeader(formikProps)}
ListFooterComponent={renderFooter(formikProps)}
/>
</View>
)}
</Formik>
</VStack>
</Box>
</ScrollView>
</KeyboardAvoidingView>
);
};
export default SignUpMember;
How can I piece this together?
I want to display data based on the day selected by the user on the calendar and displayed it on modal, this is my code for calendar
<Calendar style={styles.calendar} onDayPress={day => {
getCalendarEvent(day);
}}
markingType={'multi-dot'}
markedDates={markedDay}/>
GetcalendarEvent() is a function that call the request from rest API, This is the code
const getCalendarEvent=(day)=>{
axios.get(`${BASE_URL_COURSE}&wsfunction=core_calendar_get_calendar_day_view&year=${day.year}&month=${day.month}&day=${day.day}`)
.then(res=>{
const data = (res.data)
seteventItems(data)
setModalVisible(true)
}).catch(e=>{
console.log(`error ${e}`)
})
}
and i want to display data from GetcalendarEvent() function into modal, so i tried setModalVisible(true) inside of GetcalendarEvent() function. But it didn't worked, the data was not displayed on modal and just an empty flatlist.
this is my modal code
<View style={styles.centeredView}>
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
Alert.alert("Modal has been closed.");
setModalVisible(!modalVisible);
}}
>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<FlatList
data={eventItems}
renderItem={({item}) =>{
return (
<View>
<Text style={styles.modalText}>{item.name}</Text>
</View>
)
}} />
<Pressable
style={[styles.button, styles.buttonClose]}
onPress={() => setModalVisible(!modalVisible)}
>
<Text style={styles.textStyle}>Close</Text>
</Pressable>
</View>
</View>
</Modal>
</View>
I have an array with values i want to present and then if the user press the edit button the presentation is changed to a list of TextInput components. When done editing the user can press Save or Cancel. If Cancel is pressed the values in the textInput fields should not be saved to the original array of values.
My problem is that even when pressing Cancel the data in the original array seems to be updated.
This is the code:
`
const handlePress = (text, index) => {
const newSchedule = [...scheduleTempState]
newSchedule[index].value = text
setScheduleTempState(newSchedule)
}
const handlePress2 =()=>{
setScheduleTempState([]);
console.log("handlepress2")
setEdit(false)
}
const handlePress3 =()=>{
setScheduleTempState(scheduleState);
console.log("handlepress3")
setEdit(true)
}
return (
edit
?
<View style={styles.scheduleRow}>
<View style={styles.buttonView}>
<TouchableOpacity onPress = { ()=>{saveSchedule(projectId,scheduleState);updateClient() ;setEdit(false)}} >
<MaterialIcons name="save" size={16} color="green" />
</TouchableOpacity>
<TouchableOpacity onPress = { ()=>{handlePress2()}} >
<MaterialIcons name="cancel" size={16} color="red" />
</TouchableOpacity>
</View>
<View>
<FlatList
horizontal = {true}
data={scheduleTempState}
keyExtractor={item => item.id}
renderItem={({item, index}) => {
return (
<View style={styles.decimalInputView}>
<TextInput
style={styles.cellInput}
onChangeText={(text) => {handlePress(text, index)}}
value = {item.value} />
</View>
)
}}
/>
</View>
</View>
:
<View style={styles.scheduleRow}>
<View style={styles.buttonView}>
<TouchableOpacity onPress = { ()=>handlePress3()} >
<MaterialIcons name="edit" size={14} color="black" />
</TouchableOpacity>
</View>
<View >
<FlatList
horizontal={true}
data={scheduleState}
renderItem={renderScheduleItem}
keyExtractor={item => item.id}
/>
</View>
</View>
);
}`
I guess my problem has something to do with states not being updated, but i can not see how the edited values can be saved when i press cancel.
Problem:
You are updating the scheduleTempState by referencing your scheduleState. So when you mutate scheduleTempState, it also mutates the scheduleState.
Solution: Please use spread operator to scheduleState which can help to create a new copy of a reference.
const handlePress3 =()=>{
setScheduleTempState([...scheduleState]);
...
}
Suggestion: It would be better to use explanatory names for function. It will make the code more readable. For example:
onChangeText() instead of handlepress()
onCancelEditing() instead of handlepress2()
onEdit instead of handlepress3()
Hope you will get the idea.
Below in a code I have describe the question as comment
//This is MessagesScreen.js
<FlatList
data={messages}
keyExtractor={messages => messages.id.toString()}
renderItem={({ item }) =>
<ListItem style={styles.listItem}
title={item.title}
subTitle={item.description}
image={item.image}
DeleteIconView={ListItemDeleteAction} /*Here ListItemDeleteAction.js
is component want to pass it to
the ListItem.js. Note: I have
imported all the nessory
labries*/
onPress={() => handleDelete(item)}
//renderRightActions={ListItemDeleteAction}
/>
}
ItemSeparatorComponent={ListItemSeparator}
refreshing={refreshing}
onRefresh={() => {
setMessages([
{
id: 2,
title: 'Komail',
description: 'React-Native Developer',
image: require("../asserts/komail.jpg"),
}
])
}}
/>
This is ListItemDeleteAction.js, which I want to render in ItemList.js
//This is ListItemDeleteAction.js
function ListItemDeleteAction(props) {
return (
<View style={styles.container}>
<MaterialCommunityIcons name="trash-can" size={30} color={Colors.danger} />
</View>
);
}
Now, in ListItem.js I want to render the ListItemDeleteAction.js as I have passed as a argument. Below in code I have described as comment.
Note: I am strict to this method, render the ListItemDeleteAction as it passed as argument, which is "DeleteIconView" as parameter in ListItem.js
function ListItem({ image, title, subTitle, ImageComponent, style, onPress, DeleteIconView}) {
return (
<TouchableHighlight
//onPress={onPress}
underlayColor={Colors.light}
>
<View style={[styles.container, style]}>
{ImageComponent}
{image && <Image style={styles.image} source={image} />}
<View style={styles.parentDeatailContainer}>
<View style={styles.detailContainer}>
<Text style={{ fontWeight: "bold" }}>{title}</Text>
{subTitle && <Text>{subTitle}</Text>}
</View>
<TouchableOpacity style={styles.deleteIconContainer} onPress={onPress}>
{DeleteIconView} /* This is the place where I want to render the
ListItemDeleteAction components as I passed as argument but How? */
</TouchableOpacity>
</View>
</View>
</TouchableHighlight>
);
}
You are passing the prop wrong. When you write DeleteIconView={ListItemDeleteAction}, you aren't actually creating a JSX component. This can be solved by writing the following.
renderItem={({ item }) =>
<ListItem style={styles.listItem}
title={item.title}
subTitle={item.description}
image={item.image}
DeleteIconView={<ListItemDeleteAction />}
onPress={() => handleDelete(item)}
/>
}
Now, the prop DeleteIconView is an actual JSX component which can be rendered as usual.
I am using the Rating Element from the react-native-elements component. I noticed I can't choose more/less than 3 stars for my rating and I do not understand why.
Here is my code:
<Modal animationType={"slide"} transparent={false}
visible={this.state.showModal}
onDismiss={() => this.openModal()}
onRequestClose={() => this.openModal()}>
<View style={styles.modal}>
<Text style={styles.modalTitle}>Rating</Text>
<Rating
showRating
type="star"
imageSize={30}
onFinishRating={this.ratingCompleted}
style={{ paddingVertical: 10 }}
/>
<View style={styles.btnView}>
<Button
onPress={() => { this.handleFormSubmit() }}
color="#512DA8"
title="Submit"
style={styles.formBtn}
/>
<Button
onPress={() => { this.openModal();
this.resetForm(); }}
color="gray"
title="Cancel"
/>
</View>
</View>
</Modal>
What am I doing wrong?
I recommand to use AirbnbRating instead of Rating because it work for me.
Example code :
import {AirbnbRating } from 'react-native-elements';
<AirbnbRating
count={11}
reviews={["Terrible", "Bad", "Meh", "OK", "Good", "Hmm...", "Very Good", "Wow", "Amazing", "Unbelievable", "Jesus"]}
defaultRating={11}
size={20}
onFinishRating={rating => console.log(rating)}
/>
According to,
https://react-native-training.github.io/react-native-elements/docs/rating.html#ratingcount
you can use the prop ratingCount to set the number of rating images to display.
Try setting this to something other than 3.
Edit
Seems I misunderstood the query, please try setting readonly to false explicitly.
I would ask what do you have in function
onFinishRating={this.ratingCompleted}
I also used this component in my project and updated the state there:
<Rating
showRating
startingValue={4}
onFinishRating={rating => this.setState({ rating: rating })}
/>
Move the rating component in a function that returns the rating:
NOTE: this is a little bit strange, but it worked for me
Change your code like the following:
const RatingView=()=>{
return (
<Rating
showRating
type="star"
imageSize={30}
onFinishRating={this.ratingCompleted}
style={{ paddingVertical: 10 }}
/>
)
}
You Modal :
<Modal animationType={"slide"} transparent={false}
visible={this.state.showModal}
onDismiss={() => this.openModal()}
onRequestClose={() => this.openModal()}>
<View style={styles.modal}>
<Text style={styles.modalTitle}>Rating</Text>
<RatingView /> // Here ...
<View style={styles.btnView}>
<Button
onPress={() => { this.handleFormSubmit() }}
color="#512DA8"
title="Submit"
style={styles.formBtn}
/>
<Button
onPress={() => { this.openModal();
this.resetForm(); }}
color="gray"
title="Cancel"
/>
</View>
</View>
</Modal>