I have a TextInput in my React native project. I use an onCHangeText={(text)=>handleChange(‘postText’, text)} function to update the formData that I had set as a State Object at the beginning of the function. The result I get is whenever I type, the app restarts and refreshes, deleting former content and only writing the latest character to the text field. Worse, it hides the keypad altogether.
Here is my code:
const HomePageBuilder = ({navigation}) =>{
const [postingMedia, setPostingMedia] = useState(null);
const [selectedValue, setSelectedValue] = useState(null);
const [images, setImages] = useState([]);
const screenWidth = Dimensions.get('window').width;
const {userId, login, logout, user} = useContext(AppContext);
const [postData, setPostData] = useState({postMedia : '',
postText : '', postType : 'General'
});
const handleChange = (fieldName, value)=>{
setFormData(prevState =>({
...prevState,
[fieldName]:value
}));
}
return(<>
<Header />
<SafeAreaView style = {HomeStyles.container}>
<View style = {HomeStyles.bodyMain}>
<>
<FlatList
data = {posts}
renderItem={postBuilder}
keyExtractor={(item, index) => index.toString()}
style ={{marginBottom: 20, paddingBottom: 20}}
ListHeaderComponent={()=>(
<View style = {HomeStyles.postMakerDiv}>
<View>
<TextInput placeholder="Share some news" style = {HomeStyles.postBoxMain}
ref = {postInputRef}
// onChangeText={(text) => handleChange('postText', text)}
value = {postData.postText}
onEndEditing={(text) => setPostText(text)}
/>
</View>
<View style = {HomeStyles.imageBox}>
{images.length > 0 && (
<>
<Pressable style = {{zIndex: 1}} onPress = {()=>{
setImages([]);
}}>
<Image source = {require("../../views/resources/close-circle.png")} style = {{width: 25, height: 25, left: '96%', top: 15, zIndex: 1}}/>
</Pressable>
<ScrollView horizontal style={{ marginTop: 20, height: 320}} contentContainerStyle = {HomeStyles.picturesPreview}>
{images.map((imageUri, index) => (
<View key={index} style={{ margin: 5 }}>
<Image
source={{ uri: imageUri }}
style={{ minWidth: screenWidth * 0.9, maxWidth: screenWidth * 0.9, height: 300, borderRadius: 10 }}
/>
</View>
))}
</ScrollView>
</>
)}
</View>
<View style = {HomeStyles.imageBox}>
{
videoUri ?(
<>
<Pressable onPress = {()=>{
setVideoUri(null);
}} style = {{width: 30, height: 30, flexDirection: 'row', alignSelf: 'flex-end'}}>
<Image source = {require("../../views/resources/close-circle.png")} style = {{width: 25, height: 25, zIndex: 1, top: 10}}/>
</Pressable>
<TouchableOpacity onPress = {togglePlayback}>
<Video
source = {{uri: videoUri}}
resizeMode = "cover"
style = {{width: '100%', height: 400, borderWidth: 1, borderRadius: 30}}
ref = {videoRef}
shouldPlay = {isPlaying}
isLooping
/>
</TouchableOpacity>
</>
):(
<>
</>
)
}
</View>
<View style = {HomeStyles.postOptions}>
<Picker
selectedValue={postData.postType}
style={{ height: 50, minWidth: 130, borderWidth: 1, borderColor: 'grey' }}
onValueChange={(text) => handleChange('postType', text)}
>
<Picker.Item label="General" value="General" />
<Picker.Item label="Business" value="Business" />
<Picker.Item label="Politics" value="Politics" />
<Picker.Item label="Lifestyle" value="Lifestyle" />
<Picker.Item label="Relationship" value="Relationship" />
<Picker.Item label="Music" value="Music" />
<Picker.Item label="Art" value="Art" />
<Picker.Item label="Entertainment" value="Entertainment" />
</Picker>
<TouchableOpacity onPress={pickImages}>
{/* Modify this to call the multiple images function later.*/}
<Icon name="camera-alt" size={25} color="purple" style = {{top: 10}}/>
</TouchableOpacity>
<TouchableOpacity onPress = {chooseVideo}>
<Icon name="videocam" size={25} color="purple" style = {{top: 10}}/>
</TouchableOpacity>
<TouchableOpacity style = {HomeStyles.postBtnMain} onPress = {makePost}>
<Text style = {{color: 'white', fontWeight: 'bold', fontSize: 15}}>
Share
</Text>
{/* <Icon name="campaign" size={25} color="white" style = {{top: -2}}/> */}
</TouchableOpacity>
</View>
</View>
)}
ListEmptyComponent={()=>(
<View style = {{justifySelf : 'center', alignSelf : 'center', justifyContent : 'center', alignContent: 'center', width: 300, marginTop: 50}}>
<Text style = {{fontSize: 20, color: 'grey', textAlign: 'center'}}>
Seems you are having some internet issues.
</Text>
<TouchableOpacity onPress = {()=> navigation.navigate("Home")} style = {{backgroundColor: 'purple', justifyContent : 'center', alignContent: 'center', padding: 10, borderRadius: 10, marginTop: 30}}>
<Text style = {{textAlign: 'center', color: 'white'}}>
Try again?
</Text>
</TouchableOpacity>
</View>
)}
/>
</>
</View>
</SafeAreaView>
</>
);
The element causing this is styled with styles.postBoxMain
I have tried Isolating this TextINput by giving it it’s own state separate from the postData object. I have tried using useRef.current.value. I have tried using lodash’s debounce, none of these techniques seem to be working.
I just need the textinput field to act normally and be stored in the postData.postText object. This is not working out. I have even tried onEndEditing. Everything I have done just reflects the same error.
2
Answers
your setter is called
setPostData
but in yourhandleOnChange
you have it assetFormData
so it basically doesn’t exist and that’s why the app is breaking, just change the code insidehandleOnChange
as this:Agree with the answer by @Eduardopalacio
Adding to it:
Please see the example code here Using a single event handler for multiple fields . It shows how to use eventObject.target.name and eventObject.target.value properties to write more concise code as shown below.