ReactNative TCP Socket - reactjs

I'm trying to updates states using RN TCP Socket library : https://github.com/Rapsssito/react-native-tcp-socket
But when i received data, state is not updated (Log is correctly displayed).
const App = () => {
const [connected, setConnected] = useState('Init');
const [numberMessage, setNumberMessage] = useState(0);
const sendMessage = val => {
// client.emit('data', {message: val});
console.log(numberMessage);
};
useEffect(() => {
client.on('connect', () => {
setConnected('Connected');
});
client.on('data', async data => {
const increment = numberMessage + 1;
await setNumberMessage(increment);
console.log('received');
});
return () => {
client.destroy();
};
}, []);
return (
<SafeAreaView style={{backgroundColor: 'white', flex: 1}}>
<ScrollView style={{flex: 1}}>
<Text style={{textAlign: 'center', marginBottom: 25}}>{connected}</Text>
<Text style={{marginBottom: 10}}>{numberMessage}</Text>
<TouchableOpacity onPress={() => sendMessage('yes')}>
<Text>Send message</Text>
</TouchableOpacity>
</ScrollView>
</SafeAreaView>
);
};
I can't find a solution. Have you some tips or alternatives ?

Related

Error: Camera is not running. React native expo-camera

Having camera permissions but still camera is not running its giving a blank (black) screen.
Sometimes it runs when refreshing but after that we again trigger the camera it will give the same blank again
Versions I am using.
"expo": "^41.0.0"
"expo-barcode-scanner": "~10.1.2"
"expo-camera": "~11.0.2"
"#react-navigation/native": "^5.9.4"
Here is my code before going to next screen. I am checking for camera permissions by pressing the FAB Button.
export default function ScannerScreen(props) {
const { navigation, route } = props;
const { colors, fonts } = useTheme();
const dispatch = useDispatch();
const { translations } = useContext(LocalizationContext);
const { scanner: strings } = translations;
const [data, setData] = useState('Not yet scanned')
const openQrScanner = async () => {
const { status } = await Camera.requestPermissionsAsync();
if (status === "granted") {
navigation.navigate('QRCodeScanner');
} else {
dispatch(notify(translations.allowCamera));
}
};
const goBack = () => {
navigation.goBack()
}
useEffect(() => {
if (route.params && route.params.data) {
setData(route.params.data)
}
}, [route])
return (
<View style={styles.container}>
<GeneralStatusBar backgroundColor="#fff" barStyle="dark-content" />
<View style={styles.header}>
<TouchableRipple style={styles.backButton} onPress={goBack} borderless={true} rippleColor={colors.rippleColor}>
<Ionicons name="md-arrow-back" size={24} color={colors.regularText} />
</TouchableRipple>
<View style={{ flex: 1 }}>
<Text style={{ ...fonts.medium, fontSize: 14, color: colors.regularText }}>{strings.pay}</Text>
</View>
</View>
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ ...fonts.medium, fontSize: 16 }}>{data}</Text>
</View>
<FAB
icon={() => <MaterialIcons name="qr-code-scanner" size={24} color="white" />}
style={styles.fab}
onPress={openQrScanner}
/>
</View>
);
}
If user give the camera permissions then the will take to QRCodeScanner Screen.
export default function QRCodeScannerScreen(props) {
const { navigation, route } = props;
const { colors, fonts } = useTheme();
const { translations } = useContext(LocalizationContext);
const { scanner: strings } = translations;
const cameraRef = useRef()
const [scanned, setScanned] = useState(false);
const [flashMode, setFlashMode] = useState(false);
const [ratio, setRatio] = useState('4:3');
const { height, width } = Dimensions.get('window');
const screenRatio = height / width;
const [isRatioSet, setIsRatioSet] = useState(false);
const goBack = () => {
navigation.goBack()
}
const handleBarCodeScanned = ({ type, data }) => {
setScanned(true);
navigation.navigate('Pay', { data: data });
// console.log('Type: ' + type + '\nData: ' + data)
};
const prepareRatio = async () => {
let desiredRatio = '4:3';
if (Platform.OS === 'android') {
if (cameraRef) {
try {
const ratios = await cameraRef.current.getSupportedRatiosAsync();
let distances = {};
let realRatios = {};
let minDistance = null;
for (const ratio of ratios) {
const parts = ratio.split(':');
const realRatio = parseInt(parts[0]) / parseInt(parts[1]);
realRatios[ratio] = realRatio;
const distance = screenRatio - realRatio;
distances[ratio] = realRatio;
if (minDistance == null) {
minDistance = ratio;
} else {
if (distance >= 0 && distance < distances[minDistance]) {
minDistance = ratio;
}
}
}
desiredRatio = minDistance;
setRatio(desiredRatio);
setIsRatioSet(true);
} catch (error) {
console.log('errorMessage', error);
}
}
}
};
const setCameraReady = async () => {
if (!isRatioSet) {
await prepareRatio();
}
};
return (
<View style={styles.container}>
<GeneralStatusBar backgroundColor="#0008" barStyle="light-content" />
<Camera
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
barCodeScannerSettings={{
barCodeTypes: [BarCodeScanner.Constants.BarCodeType.qr],
}}
flashMode={flashMode ? Camera.Constants.FlashMode.torch : Camera.Constants.FlashMode.off}
type={Camera.Constants.Type.back}
style={styles.barcodeScanner}
onCameraReady={setCameraReady}
ratio={ratio}
ref={cameraRef}
/>
<View style={styles.cameraOverlay}>
<View style={styles.overlayHeader}>
<TouchableRipple style={styles.backButton} onPress={goBack} borderless={true} rippleColor={colors.rippleColor}>
<Ionicons name="md-arrow-back" size={24} color={'#fff'} />
</TouchableRipple>
<View style={{ flex: 1 }}>
<Text style={{ ...fonts.medium, fontSize: 14, color: '#fff' }}>{strings.scanAnyQr}</Text>
</View>
<TouchableRipple style={styles.backButton} onPress={() => setFlashMode(!flashMode)} borderless={true} rippleColor={colors.rippleColor}>
{flashMode ?
<MaterialCommunityIcons name="flashlight" size={20} color="white" />
:
<MaterialCommunityIcons name="flashlight-off" size={20} color="white" />
}
</TouchableRipple>
</View>
<View style={styles.scannerContainer}>
<View style={styles.scannerBox}>
{/* <View style={{ ...styles.barcodebox, borderColor: colors.button, borderWidth: 2 }}>
<Text style={{ fontSize: 12, color: "#fff" }}>Please align the QR within the scanner.</Text>
</View> */}
</View>
</View>
</View>
</View>
);
}

Load component after api is fetched

I am fetching json from API and then I want to display the component
const [jsonCat, setjsonCat] = useState([]);
useEffect(() => {
refreshCat();
}, []);
const refreshCat = async () => {
try {
console.log("refreshing categories");
setjsonCat([]);
getCat().then((response) => {
setjsonCat(response);
});
} catch (e) {
console.log(e);
}
};
const CarousalLoop = (props) => {
const BANNER_Hs = 1;
if (jsonCat.length == 0) {
return <View></View>;
}
const listItemstest = jsonCat.map((link) => {
console.log(link.name);
<View>
<Text style={{ color: "red" }}>{link.name}</Text>
</View>;
});
return (
<View style={{ height: 220, backgroundColor: "brown" }}>
{listItemstest}
</View>
);
};
And Finally my render component has
{jsonCat.length ? <CarousalLoop /> : <ActivityIndicator />}
When I run this code , Activity indicator is shown until API request is fetched and then json is also received properly , console.log(link.name)
is printing the names correctly but CarousalLoop is displayed without any listitems (just brown view component is shown) .
Either you use return keyword
const listItemstest = jsonCat.map((link) => {
console.log(link.name);
return(
<View>
<Text style={{ color: "red" }}>{link.name}</Text>
</View>
)
});
Or wrap in parenthesis
const listItemstest = jsonCat.map((link) => (
<View>
<Text style={{ color: "red" }}>{link.name}</Text>
</View>;
));
You need to return the list of items to render from listItemstest, like this.
const listItemstest = jsonCat.map((link) => {
console.log(link.name);
return <View>
<Text style={{ color: "red" }}>{link.name}</Text>
</View>;
});

react native conditionally fetch data too much re-rendering issue

I want to achieve such scenario in my application:
when the user taps on a Company for checking its details I want to show all products of the company first.
when the user taps on a Category in the Details page I want to show only products related to that category.
for both cases I need to call API with specific arguments so here's my code:
Card Details Page:
const CardDetails = (props) => {
const dispatch = useDispatch();
const companyId = props.route.params.id;
const companyName = props.route.params.companyName;
const companyImage = props.route.params.companyImage;
const companyLocation = props.route.params.companyLocation;
const [isCatLoading, setIsCatLoading] = useState(true);
const [isProductLoading, setIsProductLoading] = useState(true);
const [CompanyCategories, setCompanyCategories] = useState([]);
let products = [];
console.log(products)
const fetchCategories = async () => {
const response = await fetch(`myURL`);
const data = await response.json();
setCompanyCategories(data)
setIsCatLoading(false)
};
const fetchProducts = () => {
dispatch(SelectedProductsByCat.fetchSelectedCatProducts(companyId, [7, 8, 10, 11]))
.then(
setIsProductLoading(false)
)
}
if (setIsProductLoading) {
products = useSelector(state => state.products.availableSelectedCatProducts)
}
useEffect(() => {
fetchCategories()
}, [products])
useEffect(() => {
fetchProducts()
}, [products])
return (
<ScrollView showsVerticalScrollIndicator={false} style={styles.screen}>
<View style={styles.titleContainer}>
<Text style={styles.titleText}>{companyName}</Text>
</View>
<View style={styles.imageContainer}>
<View style={styles.mainImageContainer}>
<Image style={styles.mainImage} source={{ uri: companyImage }} />
</View>
</View>
<View style={styles.optionsContainer}>
<Option title={companyLocation} />
</View>
<View style={styles.typeSelectionContainer}>
{
isCatLoading ?
<DotIndicator color='#253D59' size={20} count={5} />
:
<ScrollView contentContainerStyle={styles.horizontalScrollContainer} horizontal={true} showsHorizontalScrollIndicator={false}>
<CategorySelection
companyId={companyId}
options={CompanyCategories.map((el, i) => {
return { id: el.id, name: el.title, icon: el.icon, selected: false }
})}
/>
</ScrollView>
}
</View>
{
isProductLoading ?
<View>
<DotIndicator color='#253D59' size={20} count={5} />
</View>
:
<View style={styles.resultsContainer}>
{
products != 'undefined' && products.length > 0 ?
products.map((el, index) => {
return (
<TouchableOpacity
key={el.id.toString()}
style={styles.resultImageContainer}
onPress={() => props.navigation.navigate('OfficeDetails', {
productId: el.id.toString(),
productName: el.productName,
productPrice: el.productPrice,
productImages: el.groupOfImage
})}
>
<Image style={styles.mainImage} source={{ uri: el.groupOfImage[0].imageAddress }} />
<View style={styles.seatsContainer}>
<Text style={styles.seatsText}>{el.productPrice} <Text style={styles.price}>₺</Text></Text>
</View>
</TouchableOpacity>
)
})
:
<View style={{ marginTop: 40 }}>
<NoData size={wp(40)} />
</View>
}
</View>
}
</ScrollView>
)
}
and this is the Categories Component:
const CategorySelection = (props) => {
const dispatch = useDispatch();
const companyId = props.companyId
const [options, setOptions] = useState(props.options.map((el, index) => {
return {
id: el.id,
name: el.name,
selected: el.selected
}
}))
const selectedCategoriesId = options.filter(el => el.selected).map(el => el.id);
useEffect(() => {
fetchProductsHandler();
}, [options])
const fetchProductsHandler = () => {
if(selectedCategoriesId.length == 0) {
dispatch(SelectedProductsByCat.fetchSelectedCatProducts(companyId, options.map((el, index) => el.id)));
}
}
const onRadioBtnClick = (item) => {
let updatedState = options.map((el) =>{
if(el.id == item.id) {
return { ...el, selected: !el.selected }
} else {
return { ...el, selected: el.selected }
}
}
);
setOptions(updatedState)
};
return (
<View style={styles.mainContainer}>
{
options.map((item, index) => {
return (
<TouchableOpacity
onPress={() => {
onRadioBtnClick(item)
}
}
key={item.id}
selected={item.selected}
style={[styles.buttonContainer, props.buttonStyle]}>
<View style={[styles.button,
item.selected == true ? styles.selectedButton : null
]}>
<Text style={[styles.buttonText,
item.selected == true ? styles.selectedButtonText : null,
{fontSize : item.name.split(' ')[0].length > 10 ? hp(1.5) : hp(2.1)}
]}>{item.name}</Text>
</View>
</TouchableOpacity>
)
})
}
</View>
)
}
and here's the screenshot of the page:
again what I need to achieve here is to show all products at first, but when the user tap on categories I need to show related products, and also when the user deselects categories all products show again.
if you need more code for the project just let me know in the comments. any help would be appreciated <3

FlatList is not rerendering upon data change

I have an array of conversations and a function that checks if the recipient is online. However when that function changes its return value (boolean), the flatlist does NOT rerender. I tried extraData but with no luck. My code is:
flatList
<FlatList
data={conversations}
extraData={isRefreshing}
renderItem={(conversation) => (
<TouchableOpacity
onPress={() => selectConversation(conversation.item)}
style={{
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
borderBottomWidth: 1,
padding: 5,
marginBottom: 5,
}}
>
<View>
<Text>{getRecipient(conversation.item).displayName}</Text>
<Text>{conversation.item.latestMessage}</Text>
</View>
{isUserOnline(conversation.item) && (
<Text style={{ color: "green" }}>ONLINE</Text>
)}
</TouchableOpacity>
)}
keyExtractor={(item) => item._id}
/>
useEffect
useEffect(() => {
let handler = (data) => {
console.log(data);
setOnlineUsers((prevState) => {
return data;
});
setRefreshing(!isRefreshing);
};
const unsubscribe = navigation.addListener("focus", () => {
console.log("focused");
socket.on("online-users-data", handler);
socket.emit("join-online-users");
getConversations();
});
return () => {
socket.emit("leave-online-users");
socket.off("online-users-data", handler);
unsubscribe();
};
}, []);
isUserOnline()
function isUserOnline(conversation) {
const user = getRecipient(conversation);
const onlineUser = onlineUsers.find((u) => u.userId === user._id);
return (
user && onlineUser && user._id.toString() === onlineUser.userId.toString()
);
}
I have solved this by adding onlineUsers to extraData. Damn it was confusing.

Invariant Violation: Text strings must be rendered within a <Text> component while using flatList

I am using flat list to display data which is coming from unsplash api. But here it keeps on complaining to saying this
Invariant Violation: Text strings must be rendered within a component
I am not even using any text component. I have no idea what is wrong here.
App.js
export default function App() {
const [loading, setLoading] = useState(true);
const [image, setImage] = useState([]);
const {height, width} = Dimensions.get('window');
const URL = `https://api.unsplash.com/photos/random?count=30&client_id=${ACCESS_KEY}`;
useEffect(() => {
loadWallpapers();
}, [])
const loadWallpapers =() => {
axios.get(URL)
.then((res) => {
setImage(res.data);
setLoading(false);
}).catch((err) => {
console.log(err)
}).finally(() => {
console.log('request completed')
})
}
const renderItem = (image) => {
console.log('renderItem', image);
return (
<View style={{height, width}}>
<Image
style={{flex: 1, height: null, width: null}}
source={{uri : image.urls.regular}}/>
</View>
)
}
return loading ? (
<View style={{flex: 1, backgroundColor: 'black', justifyContent: 'center',alignItems: 'center'}}>
<ActivityIndicator size={'large'} color="grey"/>
</View>
): (
<SafeAreaView style={{flex: 1, backgroundColor: 'black'}}>
<FlatList
horizontal
pagingEnabled
data={image}
renderItem={({ item }) => renderItem(item)} />}
/>
</SafeAreaView>
)
}
I thing data of Flatlist is null, try
<FlatList
horizontal
pagingEnabled
data = {image ? image : []}
renderItem={({ item }) => renderItem(item)} />}
/>
I needed to do something like this to make it work.
const renderItem = ({ item }) => { <---- I have destructured item here
console.log(item)
return (
<View style={{ flex: 1 }}>
</View>
);
};
<FlatList
scrollEnabled={!focused}
horizontal
pagingEnabled
data={image}
renderItem={renderItem}
/>

Resources