React Native - TextInput does not get updated and is stuck with its initial state which is empty onSubmitEditing - react-native

The setSearchTerm does not get updated and is stuck with empty string all the time when i hit "done" on the keyboard. Any suggestions?
// React Native Bottom Navigation
// https://aboutreact.com/react-native-bottom-navigation/
import React, { useState } from 'react';
import { View, Text, SafeAreaView, Dimensions, FlatList, TouchableOpacity, TextInput } from 'react-native';
import { WebView } from 'react-native-webview';
import
MaterialCommunityIcons
from 'react-native-vector-icons/MaterialCommunityIcons';
const windowWidth = Dimensions.get('window').width;
const windowHeight = Dimensions.get('window').height;
const SearchScreen = ({navigation}) => {
const [searchTerm, setSearchTerm] = useState('');
const [data, dataSet] = useState({})
const onSearchText = async() => {
alert(searchTerm);
dataSet({});
let txtSearch = searchTerm;
if(txtSearch.length > 0){
//alert(searchTerm);
let response = await fetch('https://xxxxxx',{
headers: {
'Accept': 'application/json, text/plain',
'Content-Type': 'application/json;charset=UTF-8'
},
method: 'POST',
body: JSON.stringify({ searchTerm: searchTerm }),
mode: 'no-cors',
})
response = await response.json();
alert(JSON.stringify(response.results));
//alert(JSON.stringify(response.results));
dataSet(response.results);
}else{
}
}
React.useLayoutEffect(() => {
navigation.setOptions({
headerRight: () =>
<View style={{flexDirection:'row'}}>
<TextInput
placeholder='Search Here'
onChangeText={term => setSearchTerm(term)}
onSubmitEditing={onSearchText} style={{backgroundColor:'#B2DFDB',marginRight:20,width:windowWidth - 125, padding:5, borderRadius:5,}}/>
</View>
,
});
}, [navigation, ]);
const renderItem = ({ item }) => (
<TouchableOpacity
onPress={() => navigation.navigate("Display", { url: item.url, youtube: item.youtube })}>
<View style={{flexDirection:'row', marginBottom:20,padding:10,backgroundColor:'#B2DFDB',borderRadius:10,}}>
<View pointerEvents="none" style={{}}>
<WebView style={{width:200, height:130, }} source={{ uri: item.url }} />
</View>
<View style={{ marginLeft:10, }}>
<Text style={{color:'#00796B', flexWrap: 'wrap',}}>{item.source}</Text>
<View style={{flexDirection:'row', flex:1,}}>
<Text style={{color:'#000000', fontWeight:'bold', flex:1, flexWrap: 'wrap'}}>{item.title}</Text>
</View>
<Text style={{color:'#00838F', }}>{item.category}</Text>
<Text style={{color:'#00838F', }}>{item.country}</Text>
</View>
</View>
</TouchableOpacity>
);
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={{ flex: 1 , padding: 16, backgroundColor:'#E0F2F1',}}>
{
data.length > 0 ? (
<FlatList
style={{flex:1,}}
data={data}
renderItem={renderItem}
keyExtractor={item => item.id}
/>) : <View style={{flex:1,justifyContent:'center',alignItems:'center', }}><Text style={{color:'#80CBC4', fontSize:20, textAlign:'center'}}>Nothing found, please try and search again.</Text></View>
}
</View>
</SafeAreaView>
);
}
export default SearchScreen;

You don't currently have a value assigned to the textInput field. Adding a value of searchTerm should resolve it.
React.useLayoutEffect(() => {
navigation.setOptions({
headerRight: () =>
<View style={{flexDirection:'row'}}>
<TextInput
placeholder='Search Here'
onChangeText={term => setSearchTerm(term)}
value={searchTerm}
onSubmitEditing={onSearchText} style={{backgroundColor:'#B2DFDB',marginRight:20,width:windowWidth - 125, padding:5, borderRadius:5,}}/>
</View>
,
});
}, [navigation, ]);

Related

How to put the bottomsheet to the front of the screen?

In ReactNative, the bottomsheet is displayed overlaid on the fragment.
Is there a way to make the bottomsheet rise to the top of the screenenter image description here
The bottom sheet looks opaque as in the picture, so the bottom sheet cannot be touched Please help
The code below is a shortened version
enter image description here
enter image description here
import React, { FC , Component, useState, useEffect, Fragment,useCallback, useMemo, useRef } from "react"
import { FlatList, ViewStyle, StyleSheet, View, Platform, TextInput, TouchableOpacity} from "react-native"
import {
BottomSheetModal,
BottomSheetModalProvider,
BottomSheetBackdrop,
} from '#gorhom/bottom-sheet';
const ROOT: ViewStyle = {
backgroundColor: DefaultTheme.colors.background,
flex: 1,
}
export const ChecklookupScreen: FC<StackScreenProps<NavigatorParamList, "checklookup">> = observer(function ChecklookupScreen() {
const bottomSheetModalRef = useRef<BottomSheetModal>(null);
// variables
const snapPoints = useMemo(() => ['25%', '50%'], []);
// callbacks
const handlePresentModalPress = useCallback((index: string) => {
LOG.info('handlePresentModalPress', index);
bottomSheetModalRef.current?.present();
}, []);
const handleSheetChanges = useCallback((index: number) => {
LOG.info
console.log('handleSheetChanges', index);
}, []);
const renderItem = ({ item, index }) => (
<TouchableOpacity
key={index + item.inspNo + item.spvsNo}
//style={listContainer}
onPress={throttle(() => {
onClickItem(item.inspNo,item.spvsNo);
})}
>
<View>
<Fragment>
</View>
<Button icon="magnify-expand"
mode="elevated"
style={styles.detailButton}
onPress={throttle(() => {
onClickItem(item.inspNo,item.spvsNo);
})}
// onPress={() => navigation.navigate("checkdetail")}
>
</Button>
</View>
</Fragment>
</View>
</TouchableOpacity>
);
const fetchChecklookups = async (offset: number) => {
LOG.debug('fetchChecklookups:' + offset);
setRefreshing(true);
await checklookupStore.getChecklookups(offset)
setRefreshing(false);
};
const onEndReached = () => {
if (checklookupStore?.checklookupsTotalRecord <= checklookups?.length) {
LOG.debug('onEndReached555555555');
} else {
setPage(page + 1)
fetchChecklookups(page + 1);
}
};
const [searchQuery, setSearchQuery] = React.useState('');
const onChangeSearch = query => setSearchQuery(query);
return (
<Screen preset="fixed" style={{ backgroundColor: colors.background, flex: 1, padding: 10,}}>
<View style={{ flex: 1,}}>
<View style={{ flex: 1, }}>
<Searchbar
placeholder="조회조건을 입력해주세요"
onChangeText={onChangeSearch}
value={searchQuery}
onPressIn={() => handlePresentModalPress('touch on')}
/>
<BottomSheetModalProvider>
<BottomSheetModal
backgroundStyle={{ backgroundColor: "gray" }}
style={styles.bottomSheet}
ref={bottomSheetModalRef}
index={1}
snapPoints={snapPoints}
onChange={handleSheetChanges}
>
<View style={{ marginTop: 10, marginLeft: 50, marginRight: 50, flexDirection: "row"}}>
<View style={{ flex: 1, }}>
<Button
mode="outlined"
>소속을 입력하세요
</Button>
</View>
</View>
</BottomSheetModal>
</BottomSheetModalProvider>
</Screen>
)
})
You can try with portal, wrap you bottom sheet to from another package.

How do you get 1 specific value from a prop in expo?

I've been trying to pass up this prop from CameraButton.js file that gives the UI of an image that was taken but whenever I activate the prop in the AddPost.js, it gives me all the values but when I try to get the singular value of the image like using console.log(props.route.params.image) and gives error undefined is not an object
enter image description here
but it works perfectly when export default function console.log(props.route.params) and shows
enter image description here
AddPost.JS
import { useNavigation } from "#react-navigation/core";
import React from 'react'
import {useState} from "react";
import { View, TextInput, Button } from 'react-native'
export default function AddPost(props) {
console.log(props);
const navigation = useNavigation();
const [caption, setCaption] = useState("")
const uploadImage = async () => {
const response = await fetch(uri)
}
return (
<View style={{flex: 1}}>
<TextInput
placeholder="Whats on your mind Edgers navars"
onChangeText={(caption) => setCaption(caption)}
/>
<Button title = "Take A Photo" onPress={() => navigation.navigate("CameraButton")}
/>
<Button title = "Save" onPress={() => uploadImage()}
/>
</View>
)
}
CameraButton.Js
import { Camera, CameraType } from 'expo-camera';
import { useNavigation } from "#react-navigation/core";
import { useState } from 'react';
import { Button, StyleSheet, Text, TouchableOpacity, View, Image } from 'react-native';
import * as ImagePicker from 'expo-image-picker';
export default function App() {
const navigation = useNavigation();
const [type, setType] = useState(Camera.Constants.Type.back)
const [permission, requestPermission] = Camera.useCameraPermissions();
const [image, setImage] = useState(null);
const [camera, setCamera] = useState(null);
const takePicture = async () => {
if(camera){
const data = await camera.takePictureAsync(null);
setImage(data.uri);
}
}
if (!permission) {
// Camera permissions are still loading
return <View />;
}
if (!permission.granted) {
// Camera permissions are not granted yet
return (
<View style={styles.container}>
<Text style={{ textAlign: 'center' }}>
We need your permission to show the camera
</Text>
<Button onPress={requestPermission} title="grant permission" />
</View>
);
}
function toggleCameraType() {
setType((current) => (
current === Camera.Constants.Type.back ? Camera.Constants.Type.front : Camera.Constants.Type.back
));
}
// No permissions request is necessary for launching the image library
let openImagePickerAsync = async () => {
let permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (permissionResult.granted === false) {
alert("Permission to access camera roll is required!");
return;
}
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
if (!result.cancelled) {
setImage(result.uri);
}
}
return (
<View style={styles.container}>
<Camera ref={ref => setCamera(ref)} style={styles.camera} type={type}>
<View style={styles.buttonContainer}>
<TouchableOpacity
style={styles.button}
onPress={toggleCameraType}>
<Text style={styles.text}>Flip Camera</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={() => takePicture()}>
<Text style={styles.text}>Take Picture</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={openImagePickerAsync}>
<Text style={styles.text}>Choose Picture</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={() => navigation.navigate('AddPost', {image})}>
<Text style={styles.text}>Save Picture</Text>
</TouchableOpacity>
</View>
</Camera>
{image &&<Image source={{uri: image}}style={styles.camera}/>}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
camera: {
flex: 1,
},
buttonContainer: {
flex: 1,
flexDirection: 'row',
backgroundColor: 'transparent',
margin: 64,
},
button: {
flex: 1,
alignSelf: 'flex-end',
alignItems: 'center',
},
text: {
fontSize: 24,
fontWeight: 'bold',
color: 'white',
},
});
You have to get the uri from the route object.
const response = await fetch(props.route.params?.image)
In you file CameraButton.js set the navigation for this:
<TouchableOpacity
style={styles.button}
onPress={() => navigation.navigate('AddPost', {
image: image
})}>
<Text style={styles.text}>Save Picture</Text>
</TouchableOpacity>
Be sure that the state image contains only the uri and not and object
Try props[0].route.params.image.

Searchable flat list react native

I am trying to search items in a flatlist, whenever i type in the search bar it only take one letter and closes the keyboard and the value inside the search bar disappear,
example when i type "george" it only takes the letter g and re-render a list of names containing the letter g and delete what's inside the search bar
how can i fix this ?
import React, { useState, useEffect } from 'react';
import { ScrollView } from 'react-native';
import { View, Text, FlatList, ActivityIndicator, SafeAreaView, TouchableOpacity } from 'react-native';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { Divider, SearchBar } from 'react-native-elements'
const Item = ({ name, lastName }) => (
<View>
<Text style={{ fontSize: 17, color: '#666', marginBottom: 10 }}>Full name: {name} {lastName}</Text>
</View>);
function Clients({ navigation }) {
const [isLoading, setLoading] = useState(true);
const usersApi = 'https://reqres.in/api/users'
const [users, setUsers] = useState([]);
const [search, setSearch] = useState("");
const [masterData, setMasterData] = useState("");
const fetchJson = async (userApi) => {
const response = await fetch(userApi);
return response.json()
}
useEffect(() => {
fetchJson(usersApi)
.then((users) => {
setUsers(users.data);
setMasterData(users.data);
})
.catch((error) => (alert(error)))
.finally(() => setLoading(false));
}, []);
const itemSeparator = () => {
return (
<Divider style={{ width: "105%", marginVertical: 3, alignSelf: 'center' }} />
)
}
const renderHeader = () => {
return (
<SearchBar
placeholder="Type Here..."
lightTheme
round
onChangeText={text => searchFilterFunction(text)}
autoCorrect={false}
/>
);
};
const searchFilterFunction = text => {
setSearch(text);
const newData = masterData.filter(item => {
const itemData = `${item.first_name.toUpperCase()} ${item.last_name.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setUsers(newData);
};
const renderItem = ({ item }) => (
<TouchableOpacity style={{
flex: 1,
padding: 10
}}
onPress={() => { navigation.navigate('Client', { item: item }); }}
underlayColor='#ccc'
activeOpacity={0.1} >
<Item name={item.first_name} lastName={item.last_name} />
</TouchableOpacity>
);
console.log(search)
console.log(users)
return (
<SafeAreaProvider>
<SafeAreaView>
<Text style={{ color: '#666', margin: 15, fontSize: 20 }}>Clients actuels</Text>
<View style={{
width: '96%',
backgroundColor: 'white',
borderRadius: 5,
alignSelf: 'center',
marginTop: 20,
}}>
<View style={{ margin: 15 }}>
{isLoading ? <ActivityIndicator size="large" /> :
<FlatList
data={users}
renderItem={renderItem}
ItemSeparatorComponent={itemSeparator}
ListHeaderComponent={renderHeader}
keyExtractor={item => item.id.toString()}
value={search}
/>}
</View>
</View>
</SafeAreaView>
</SafeAreaProvider>
);
}
export default Clients;

Show user info in Profile bottom tab navigator after login successfully from Login screen?

I have a React Native project. My problem is that when login successfully from the Login screen, I navigate to the Home screen. Here I have a bottom navigator tab including Home and Profile. I want to show the user info in Profile but I don't know how to do it. Can anyone give me some ideas?
Here is my code
import React, {useState} from 'react';
import {
View,
StyleSheet,
Text,
Image,
ScrollView,
Dimensions,
TouchableOpacity,
TextInput,
Alert,
} from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';
import Account from '../component/Account';
const {width: WIDTH} = Dimensions.get('window');
const Login = (props) => {
let [email, setEmail] = useState('');
let [password, setPassword] = useState('');
let [isFocused, setIsFocused] = useState(0);
const _onPress = (index) => {
setIsFocused(index);
};
const dangnhap = (params) => {
if (email.length == 0 || password.length == 0) {
Alert.alert('Thông Báo', 'Hãy nhập đầy đủ email và mật khẩu');
return;
}
try {
fetch('http://192.168.1.10:8080/api/auth/signin', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json ; charset=utf-8',
},
body: JSON.stringify(params),
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
if (responseJson.status == 200) {
props.navigation.push('Home', email);
props.navigation.navigate('Home');
} else {
Alert.alert('Thông báo', 'Đăng nhập thất bại');
}
});
} catch (error) {
console.log(error);
}
};
return (
<ScrollView style={{backgroundColor: 'white'}}>
<View style={styles.container}>
<Image
source={require('../assets/images/login.png')}
resizeMode="center"
style={styles.image}
/>
<Text style={styles.textTitle}>Chào mừng trở lại</Text>
<Text style={styles.textBody}>Đăng nhập vào tài khoản sẵn có</Text>
<View style={{marginTop: 10}} />
<View style={styles.inputContainer}>
<Icon
name="mail"
size={25}
color="#59B7C9"
style={styles.inputIcon}
/>
<TextInput
onChangeText={(value) => setEmail(value)}
placeholder="Email"
style={[
styles.input,
{borderColor: isFocused == 1 ? '#59B7C9' : 'black'},
]}
onFocus={() => _onPress(1)}
/>
</View>
<View style={styles.inputContainer}>
<Icon
name="lock-closed"
size={25}
color="#59B7C9"
style={styles.inputIcon}
/>
<TextInput
placeholder={'Mật khẩu'}
pass={true}
onChangeText={(value) => setPassword(value)}
style={[
styles.input,
{borderColor: isFocused == 2 ? '#59B7C9' : 'black'},
]}
secureTextEntry={true}
onFocus={() => _onPress(2)}
/>
</View>
<View style={{width: '90%'}}>
<TouchableOpacity
onPress={() => props.navigation.navigate('Forgot')}
style={([styles.textBody], {alignSelf: 'flex-end'})}>
<Text style={[styles.textBody, {color: 'blue'}]}>
Quên mật khẩu?
</Text>
</TouchableOpacity>
</View>
<View style={styles.buttonContainer}>
<TouchableOpacity
style={styles.buttonLogin}
onPress={() => {
const newUser = {
Email: email,
Password: password,
};
dangnhap(newUser);
}}>
<Text style={styles.buttonText}>Đăng nhập</Text>
</TouchableOpacity>
</View>
<Text style={styles.textBody}>Hoặc kết nối với</Text>
<View style={{flexDirection: 'row'}}>
<Account color="#3b5c8f" icon="facebook" title="Facebook" />
<Account color="#ec482f" icon="google" title="Google" />
</View>
<View style={{flexDirection: 'row', marginVertical: 5}}>
<Text style={styles.textBody}>Chưa có tài khoản?</Text>
<Text
style={[styles.textBody, {color: 'blue'}]}
onPress={() => props.navigation.navigate('Signup')}>
Đăng ký
</Text>
</View>
</View>
</ScrollView>
);
};
This might help
import {AsyncStorage} from 'react-native';
if (responseJson.status == 200) {
AsyncStorage.setItem('email', 'email#email.com');
props.navigation.navigate('Home');
}
Profile.js
import { AsyncStorage } from 'react-native';
export default const Profile = props => {
const [email, setEmail] = useState('');
useEffect(() => {
retrieveData();
}, []);
const retrieveData = async () => {
const email = await AsyncStorage.getItem('email');
setEmail(email);
};
render(){
return {
<View>
<Text>{email}</Text>
</View>
}
}
}

React Native retrieving API data source.uri should not be an empty string

I am trying to retrieve data from an API (https://developers.zomato.com/documentation) and get title of restaurants and an image with it. However when I try to load an image I get a warning source.uri should not be an empty string.
Here is my code as it stands:
async componentDidMount() {
let id = this.props.navigation.state.params.category
let result;
try {
result = await axios.request({
method: 'get',
url: `https://developers.zomato.com/api/v2.1/search?category=${id}`,
headers: {
'Content-Type': 'application/json',
'user-key': "a31bd76da32396a27b6906bf0ca707a2",
},
})
} catch (err) {
err => console.log(err)
}
this.setState({
isLoading: false,
data: result.data.restaurants
})
}
render() {
return (
<View>
{
this.state.isLoading ?
<View style={{ flex: 1, padding: 20 }}>
<ActivityIndicator style={{color:'red'}} />
</View> :
(
this.state.data.length == 0 ?
<View style={{ flex: 1, padding: 20 }}>
<Text style={{ color: '#000', fontWeight: 'bold' }}>No restaurants from selected category</Text>
</View> :
<FlatList
style={{ marginBottom: 80 }}
keyExtractor={item => item.id}
data={this.state.data}
renderItem={({ item }) =>
<TouchableHighlight onPress={()=> console.log(item.restaurant.thumb)}>
<Card image={item.restaurant.thumb} style={styles.container}>
<Image resizeMode='contain' source={{ uri: item.restaurant.thumb }}/>
<Text style={{color:'#000',fontWeight:'bold'}}>{item.restaurant.name} </Text>
</Card>
</TouchableHighlight>
}
/>
)
}
</View>
);
}
as you can see when I touch the any of the cards I am console logging the link of the image uri and it shows up perfectly. Why is that when the app loads the images they are empty strings yet when I load it though console log the link shows up perfectly?
I am using axios to load my API
here is an expo snack link: https://snack.expo.io/r1XTaw4JU
So i got 2 issues, one is in the card component you were not providing the uri properly it should be image={{uri:item.restaurant.thumb}} and secondly for newyork your entity id must be
To search for 'Italian' restaurants in 'Manhattan, New York City',
set cuisines = 55, entity_id = 94741 and entity_type = zone
Its as per zomato docs,so do check out that. and find expo link : expo-snack
import React from 'react';
import {
View,
Text,
FlatList,
StyleSheet,
Button,
TouchableHighlight,
ActivityIndicator,
} from 'react-native';
import { createAppContainer } from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';
import { Card, Image } from 'react-native-elements';
import Constants from 'expo-constants';
import axios from 'axios';
export default class CategoryScreen extends React.Component {
constructor(props){
super(props);
this.state={
data : [],
isVisible: true,
city : '94741'
}
}
async componentDidMount() {
let id = "3"
let city = this.state.city
let result;
try {
result = await axios.request({
method: 'get',
url: `https://developers.zomato.com/api/v2.1/search?entity_id=${city}&entity_type=zone&category=${id}`,
headers: {
'Content-Type': 'application/json',
'user-key': "a31bd76da32396a27b6906bf0ca707a2",
},
})
} catch (err) {
err => console.log(err)
}
this.setState({
isLoading: false,
data: result.data.restaurants
})
console.log(result)
console.log(data)
}
render() {
return (
<View>
{
this.state.isLoading ?
<View style={{ flex: 1, padding: 20 }}>
<ActivityIndicator style={{color:'red'}} />
</View> :
(
this.state.data.length == 0 ?
<View style={{ flex: 1, padding: 20 }}>
<Text style={{ color: '#000', fontWeight: 'bold' }}>No restaurants from selected category</Text>
</View> :
<FlatList
style={{ marginBottom: 80 }}
keyExtractor={item => item.id}
data={this.state.data}
renderItem={({ item }) =>
<TouchableHighlight onPress={()=> alert(item.restaurant.location.city)}>
<Card image={{uri:item.restaurant.thumb}} style={styles.container}>
<Text style={{color:'#000',fontWeight:'bold'}}>{item.restaurant.name} </Text>
</Card>
</TouchableHighlight>
}
/>
)
}
</View>
);
}
};
const styles = StyleSheet.create({
});