Currently trying to setup react-native-action-sheet and getting an invalid hook call
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
I followed the example and wrapped my wrapped your top-level component with even when using hooks.
export default () => (
<ActionSheetProvider>>
<App />
</<ActionSheetProvider>>
);
Wondering if it's the way I set this up:
import { Linking } from 'react-native';
import { useActionSheet } from '#expo/react-native-action-sheet';
export const SideButton = () => {
const { showActionSheetWithOptions } = useActionSheet();
const cancelButtonIndex = 1;
const options = ['Email', 'Cancel'];
const title = 'Email Me';
const message = 'Let me know your issues';
return showActionSheetWithOptions(
{
options,
cancelButtonIndex,
title,
message,
},
(buttonIndex) => {
if (buttonIndex === 0) {
Linking.openURL('mailto:_____').catch();
} else {
return;
}
}
);
};
Or even how I call it here:
import { Linking, Text, TouchableOpacity, View } from 'react-native';
import { SideButton } from './utils/HelpPopUp';
const ButtonContainer = () => (
<TouchableOpacity>
<Text onPress={() => Linking.openURL('_MY_WEBSITE_').catch()}>Checkout my stuff</Text>
</TouchableOpacity>
);
const Menu = (props) => {
return (
<View>
<ButtonContainer />
</View>
);
};
export default Menu;
Sorry, my answer would be to suggest an alternative rather than answer your question and present the component I use myself. I did not use the package you mentioned in the topic, but I tried with a different package before, it does the same job. https://www.npmjs.com/package/react-native-actions-sheet
This is the custom component I used.
import React from 'react';
import {StyleSheet, Text, View} from 'react-native';
import ActionSheet from 'react-native-actions-sheet';;
const CustomActionSheet = React.forwardRef(({children, title}, ref) => {
return (
<ActionSheet
ref={ref}
headerAlwaysVisible={true}
containerStyle={[
styles.containerStyle,
{backgroundColor: '#FFF'},
]}
CustomHeaderComponent={
<View style={[styles.header, {backgroundColor: '#4ac'}]}>
<Text style={styles.title}>
{title}
</Text>
</View>
}>
{children}
</ActionSheet>
);
});
const styles = StyleSheet.create({
header: {
height: 50,
justifyContent: 'center',
padding: 5,
},
title: {
color: '#FFF',
fontSize: globalStyles.titleText.fontSize,
},
containerStyle: {
borderRadius: 0,
},
});
export default CustomActionSheet;
Usage:
import React, { createRef } from "react";
import {View, Text} from "react-native";
import CustomActionSheet from './CustomActionSheet';
const actionSheetRef = createRef();
const AnythingPage = () => {
return (
<View>
<Text onPress={() => actionSheetRef.current?.show()}>
Open Custom Sheet
</Text>
<CustomActionSheet ref={actionSheetRef} title={'Title'}>
<View>
<Text>Add anything in it.</Text>
</View>
</CustomActionSheet>
</View>
)
}
You can develop a structure that will be used in the whole application by going through these.
Related
I'm making a react native app on Expo, but the whole app crashes everytime I try to get into this one page. This is my first time using react native, and I'm still a beginner to react, but I can't see what's causing the issue. The error I'm getting is Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it., but I can't see where
import { StyleSheet, Text, View, TouchableOpacity, ScrollView, TextInput } from 'react-native'
import React, { useState, useEffect } from 'react'
// import CartCard from '../Components/CartCard'
import ItemCard from '../Components/ItemCard'
const Cart = ({navigation}) => {
const [details, setDetails] = useState([])
useEffect(()=>{
getData()
}, [])
const getData = async() => {
try {
const getValues = await AsyncStorage.getItem('object')
if(getValues !== null){
console.log(JSON.parse(getValues))
setDetails(getValues)
// const objectValues = JSON.parse(getValues)
// setDetails(objectValues)
// getValues.forEach(object => {
// console.log("id:", object.id)
// setToyId(object.id)
// })
}
}catch(error){
console.log('getData didnt work')
}
}
const [cardholder, setCardholder] = useState('');
const [cardNumber, setCardNumber] = useState('');
const [expiryDate, setExpiryDate] = useState('');
const [cvc, setCvc] = useState('');
const [allItems, setAllItems] = useState(0);
const [total, setTotal] = useState(0)
const clearCart = () => {
console.log('cc')
}
const countAllItems = () => {
console.log('cai')
}
const countTotal = () => {
console.log('ct')
}
return (
<ScrollView style={{backgroundColor: 'white', height: '100%'}}>
<ItemCard />
<View>
<View style={styles.payment}>
<Text>Your Shopping Cart</Text>
<View>
<Text value={allItems} onChangeText={(value)=>{setAllItems(value)}}>Overall Items: {countAllItems}</Text>
<Text value={total} onChangeText={(value)=>{setTotal(value)}}>Total Price: ${countTotal}.00</Text>
</View>
</View>
<Text>Payment</Text>
<TextInput placeholder='Cardholder Name' style={styles.inputsLong} placeholderTextColor='black' value={cardholder} onChangeText={(value)=>setCardholder(value)}/>
<TextInput placeholder='Card Number' style={styles.inputsLong} placeholderTextColor='black' value={cardNumber} onChangeText={(value)=>setCardNumber(value)}/>
<View style={styles.shortForm}>
<TextInput placeholder='MM/YY' style={styles.inputsShort} placeholderTextColor='black' value={expiryDate} onChangeText={(value)=>setExpiryDate(value)} />
<TextInput placeholder='CVC' style={styles.inputsShort} placeholderTextColor='black' value={cvc} onChangeText={(value)=>setCvc(value)}/>
</View>
<View style={styles.buttonRow}>
<TouchableOpacity>
<Text style={styles.cancelButton} onPress={clearCart}>Cancel Order</Text>
</TouchableOpacity>
<TouchableOpacity>
<Text style={styles.orderButton} onPress={()=>navigation.navigate('ConfirmScreen')}>Place Order</Text>
</TouchableOpacity>
</View>
</View>
</ScrollView>
)
}
export default Cart
const styles = StyleSheet.create({ // styles })
ItemCard component doesn't take any parameters yet because I'm having problems storing data and passing data between pages, but this is what the component looks like in its current state:
import { StyleSheet, Text, View, ScrollView } from 'react-native'
import React from 'react'
const ItemCard = () => {
return (
<ScrollView>
<View style={styles.itemSection}>
<View style={styles.card}></View>
</View>
</ScrollView>
)
}
export default ItemCard
const styles = StyleSheet.create({ // styles })
For this warning
Warning: Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.
you have to call the functions
eg. countTotal()
<Text value={total} onChangeText={(value)=>{setTotal(value)}}>Total Price: ${countTotal()}.00</Text>
if you are using onPress then like this
<Text style={styles.cancelButton} onPress={()=>clearCart()}>Cancel Order</Text>
I've been trying to replace a view in React Native, but to no success. The app closes without errors whenever I try <TouchableOpacity onPress={() => {handleChangeMyView();}}> :
What am I doing wrong? How can I make it work?
Thank you all in advance.
import React, {
useState
} from 'react';
import {
SafeAreaView,
View,
TouchableOpacity,
} from 'react-native';
import MyInitialView from './MyInitialView';
const SiteContainer = () => {
let MyDynamicView = () => {
return (
<View></View>
);
};
const [MyDynamicViewArea, setMyDynamicViewArea] = useState(MyInitialView);
const handleChangeMyView = () => {
setMyDynamicViewArea(MyDynamicView);
};
return (
<SafeAreaView>
{MyDynamicViewArea}
<TouchableOpacity onPress={() => {handleChangeMyView();}}>
<View>
<FontAwesome name="quote-left"></FontAwesome>
</View>
</TouchableOpacity>
</SafeAreaView>
);
};
export default SiteContainer;
MyInitialView :
import React from 'react';
import {
View
} from 'react-native';
export default function MyInitialView() {
return (
<View></View>
);
}
You can use boolean value for viewing MyInitialView using useState
const [toViewMyInitialView, setToViewMyInitialView] = useState(false);
and in handleChangeMyView function set the above value as true
const handleChangeMyView = () => {
setToViewMyInitialView(true);
};
And in the SiteContainer
<SafeAreaView style={styles.siteContainer}>
// here I don't know a way to display a component in react-native, so
// you need to display the component MyInitialView if the
// toViewMyInitialView is true and when toViewMyInitialView id false it
// display MyDynamicViewArea
{toViewMyInitialView && <MyInitialView/>}
{!toViewMyInitialView && <MyDynamicViewArea/>}
<TouchableOpacity onPress={() => {handleChangeMyView()}}>
<View>
<FontAwesome name="quote-left"></FontAwesome>
</View>
</TouchableOpacity>
</SafeAreaView>
I'm using react-native-toast-notifications package for showing in-app notifications.
I'm trying to integrate it for showing notifications when a chat arrives. But this notification is also being displayed on the chat room screen where the one-to-one chat happens.
How can I prevent the notification being appeared on the chat room screen?
This is my provider component
<ToastProvider
swipeEnabled={true}
placement="top"
duration={5000}
animationType="zoom-in"
animationDuration={300}
renderType={{
message_toast: (toast) => <ToastContainer toast={toast} />,
}}
>
<SymbolsProvider>
<Navigation />
</SymbolsProvider>
</ToastProvider>
I'm using the useToast() hook provided by the package to show notifications
const toast = useToast();
toast.show(socketMessage.username + " Sent a message", {
position: "bottom",
duration: 3000,
style: toastStyle,
type: "success",
});
Sent a message
This notification is appearing on the chat room screen also which should not be happening.
Here's an example base on the comment under the question:
import { ToastProvider } from 'react-native-toast-notifications'
import {NavigationContainer} from '#react-navigation/native'
import Screens from './screens/index'
export default function App() {
return (
<ToastProvider>
<NavigationContainer>
<Screens />
</NavigationContainer>
</ToastProvider>
);
}
import React from 'react';
import {
SafeAreaView,
View,
StyleSheet,
TouchableOpacity,
Text,
} from 'react-native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import { createDrawerNavigator } from '#react-navigation/drawer';
import { useNavigation } from '#react-navigation/native';
import { useToast } from 'react-native-toast-notifications';
const Stack = createNativeStackNavigator();
const Drawer = createDrawerNavigator();
const ToastButton = ({ style}) => {
const toast = useToast();
const navigation = useNavigation();
const navState = navigation.getState();
console.log(navState.routeNames);
const currentRoute = navState.routeNames[navState.index];
const onPress = () => {
if (currentRoute != 'Chat') toast.show('Toast from ' + currentRoute);
};
return (
<TouchableOpacity style={[styles.container, style]} onPress={onPress}>
<Text>Show Toast</Text>
</TouchableOpacity>
);
};
const HomeScreen = (props) => {
return (
<View style={styles.flex}>
<ToastButton />
</View>
);
};
const ChatScreen = (props) => {
return (
<View style={styles.flex}>
<ToastButton />
</View>
);
};
export default function ScreenIndex(props) {
return (
<SafeAreaView style={{ flex: 1 }}>
<Drawer.Navigator useLegacyImplementation={true}>
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Chat" component={ChatScreen} />
</Drawer.Navigator>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
flex: {
flex: 1,
backgroundColor: '#eef',
},
});
I have build a search engine and I am able to fetch data successfully the only thing I want to do is whenever that searched field is selected, it will show the details. (There are further details are also present like age,house_no etc.) It is like another screen have to come with full details.
I am stuck here, please help me out. It is like navigation to another screen with full details for now I am using alert command to show the some details I want another screen please. Thanks.
import React, {useState, useEffect} from 'react';
import {
SafeAreaView,
Text,
StyleSheet,
View,
FlatList,
TextInput,
} from 'react-native';
import { db } from '../firebase';
const App = () => {
const [search, setSearch] = useState('');
const [filteredDataSource, setFilteredDataSource] = useState([]);
const [masterDataSource, setMasterDataSource] = useState([]);
useEffect(() => {
const fetchData = async () => {
const data = await db
.collection('Data')
.get();
setFilteredDataSource(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
setMasterDataSource(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
};
fetchData();
}, []);
const searchFilterFunction = (text) => {
if (text) {
const newData = masterDataSource.filter(
function (item) {
const itemData = item.FM_NAME_EN + item.EPIC_NO + item.MOBILE_NO
? item.FM_NAME_EN.toUpperCase() + item.EPIC_NO.toUpperCase() + item.MOBILE_NO
: ''.toUpperCase();
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setFilteredDataSource(newData);
setSearch(text);
} else {
setFilteredDataSource(masterDataSource);
setSearch(text);
}
};
const ItemView = ({item}) => {
return (
<Text
style={styles.itemStyle}
onPress={() => getItem(item)}>
{item.FM_NAME_EN}
{'\n'}
{item.GENDER.toUpperCase()}
</Text>
);
};
const ItemSeparatorView = () => {
return (
// Flat List Item Separator
<View
style={{
height: 0.5,
width: '100%',
backgroundColor: '#C8C8C8',
}}
/>
);
};
const getItem = (item) => {
alert('Name : ' + item.FM_NAME_EN + ' Epic_no : ' + item.EPIC_NO);
};
return (
<SafeAreaView style={{flex: 1}}>
<View style={styles.container}>
<TextInput
style={styles.textInputStyle}
onChangeText={(text) => searchFilterFunction(text)}
value={search}
underlineColorAndroid="transparent"
placeholder="Search Here"
/>
<FlatList
data={filteredDataSource}
keyExtractor={(item, index) => index.toString()}
ItemSeparatorComponent={ItemSeparatorView}
renderItem={ItemView}
/>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
backgroundColor: 'white',
},
itemStyle: {
padding: 10,
},
textInputStyle: {
height: 40,
borderWidth: 1,
paddingLeft: 20,
margin: 5,
borderColor: '#009688',
backgroundColor: '#FFFFFF',
},
});
export default App;
first of all, you have to create ItemDetails.js as the new component for the new screen:
import React from 'react';
import {Text, View} from 'react-native';
const ItemDetails= () => {
return (
<View>
<Text>ItemDetails screen</Text>
</View>
);
};
export default ItemDetails;
then, make sure to install react native navigation and go to create a new screen:
<Stack.Navigator
screenOptions={{
headerShown: false,
}}>
<Stack.Screen name="ItemDetails" component={ItemDetails} />
</Stack.Navigator>
then get back to the app component and modify your getItem function to this:
const getItem = item => {
navigation.navigate('ItemDetails', {item});
};
this is how you tell the application that it has to move to another screen, and you sent the specific item with it, now let's modify our ItemDetails.js to see the data:
const ItemDetails = ({route}) => {
//console.log(route.params) so you can know how to access whatever you want to print
return (
<View>
<Text>{route.params.item.item.FM_NAME_EN}</Text>
</View>
);
};
If I understood your question correctly, you need another route:
First, create a component for the new page that will display the details:
ItemDetails.js:
import { useParams } from 'react-router-dom' //You will get the params from the url
import {useState, useEffect} from 'react'
export const ItemDetails = props => {
const { id } = useParams()
const [item, setItem] = useState(null)
useEffect(() => {
if(id){
const itemSelected = /* get your item by id */
setItem(itemSelected)
}
}, [id])
return(
<p> {item.name} </p>
)
}
Wherever you define your routes:
import {ItemDetails} from './path/to/ItemDetails/'
<Switch>
...
<Route exact path="/item/:id" component={ItemDetails} />
...
<Switch>
Lastly, wrap your jsx with react-router link:
import { Link } from 'react-router-dom'
...
return (
<Link to={`/item/${item.id}`}>
<Text
style={styles.itemStyle}
{item.FM_NAME_EN}
{'\n'}
{item.GENDER.toUpperCase()}
</Text>
</Link>
);
I am trying to implement a react native image crop view and I am using :
https://github.com/hhunaid/react-native-image-crop-tools#readme
After a bit of fixing it works and apparenty there is automatically an output generated:
https://ibb.co/SBLvFGY
My question is, how can I get the value of the useRef Hook, since I want to store it in redux, it all is immensly confusing to me, the code :
import React, { useState, useRef } from 'react';
import { Button, StatusBar, StyleSheet, View, Image } from 'react-native';
import { CropView } from 'react-native-image-crop-tools';
import ImagePicker from 'react-native-image-picker';
import { connect } from 'react-redux';
import { changeNewIdeaImage } from '../../redux/actions/';
const TestImageCropper = () => {
const [uri, setUri] = useState();
const cropViewRef = useRef();
return (
<>
<StatusBar barStyle="dark-content" />
<View style={styles.container}>
<Button
title={'Pick Image'}
onPress={() => {
ImagePicker.launchImageLibrary(
{ noData: true },
(response) => {
setUri(response.uri);
}
);
}}
/>
{uri !== undefined && (
<CropView
sourceUrl={uri}
style={styles.cropView}
ref={cropViewRef}
onImageCrop={(res) => console.warn(res)}
keepAspectRatio
aspectRatio={{ width: 4, height: 4 }}
/>
)}
<Button
title={'Get Cropped View'}
onPress={() => {
cropViewRef.current.saveImage(true, 90);
}}
/>
</View>
</>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
cropView: {
flex: 1,
backgroundColor: 'red',
},
});
const mapStatetoProps = (state: any) => {};
export default TestImageCropper;
Now this is the most confusing part to me.Where does the saveImage view function even come from and how can I hook it up, so that I can save the Image uri in Redux, to display it?
<Button
title={'Get Cropped View'}
onPress={() => {
cropViewRef.current.saveImage(true, 90);
}}
/>
Thanks in advance!
The saveImage() seems like a method coming from CropView. Ref is simply storing - in your case - the rendered CropView element, so cropViewRef.current is basically the CropView in your TestImageCropper component, and you call it's built-in method with cropViewRef.current.saveImage(true, 90);
What not clear to me, is what is it that you want to store in redux? The value of the ref is the element itself.