React Native Touchable Opacity - javascript

I have this code, in which TouchableOpacity is not working and i don't know why:
const Box = (props) => {
return (
<View>
<TouchableOpacity onPress={() => {props.callBackProp(); props.budCallBackProp(props.name)}}>
<View style={styles.inputBox}>
<Text style={styles.testText}>{props.name}</Text>
</View>
</TouchableOpacity>
</View>
);
}
What is wrong here?
Edit:
At first, i click on this blue button with "budynek" text inside it, which opens something that looks like a list. Then after i click on some option i want it to dissapear, which is what these callbacks are for. I wrapped each option in this TouchableOpacity component but nothing happens after i click it - there is no effect of a click. A view which holds these "Box" component is absolutely positioned. Here is rest of the code:
return (
<View style={styles.rozwijanaPoz}>
<Pusty/>
<Box name={"budynek 1"} callBackProp={props.callBack} budCallBackProp={props.budCallBack}/>
<Box name={"budynek 2"} callBackProp={props.callBack} budCallBackProp={props.budCallBack}/>
<Box name={"budynek 3"} callBackProp={props.callBack} budCallBackProp={props.budCallBack}/>
</View>
);
}
const styles = StyleSheet.create({
rozwijanaPoz: {
position: "absolute",
left: 60,
},
});
And the main container:
<TouchableOpacity onPress={() => setIsVisible(true)}>
<View style={styles.budynekContainer}>
<Text style={styles.budynekTekst}>{budynekText}</Text>
{isVisible ?
<Rozwijana callBack={visibleCallBack} budCallBack={budynekCallBack}/>
: null}
</View>
</TouchableOpacity>

Related

In react-native, how to add active class to selected menu option

I have the following menu options in the following structure:
const menuOptions = [
{
route: 'RegisterStack',
label: 'Register',
size: 25,
},
{
route: 'LoginStack',
label: 'Login',
size: 25,
},
{
route: 'DashboardStack',
label: 'Dashboard',
size: 25,
}
];
and here's my remaining code with component state and the rest of the code:
const [activeLink, setActiveLink] = useState('');
const navigation = useNavigation();
<View>
{menuOptions.map((stack, index) => {
return (
<TouchableOpacity
key={index}
style={[
styles.menuStyle,
index === activeLink
? {backgroundColor: 'red'}
: {backgroundColor: 'white'}
]}
onPress={() => navigation.navigate(stack.route)}>
<Icon
name={stack.icon}
color={stack.color}
size={stack.size}
style={{
marginRight: mainMenuOpen ? '10%' : 0,
}}
onPress={() => setActiveLink(index)}
/>
<Text style={{width: '70%', fontWeight: '500'}}>
{stack.label}
</Text>
</TouchableOpacity>
);
})}
</View>
With the current code, I can see active class taking place but it seems to broke the navigation and won't route to a different page when click on it. The navigation starts working fine when I remove the following onPress method from Icon onPress={() => setActiveLink(index)}.
Can someone please help me how can I make this work?
The problem here is that you are nesting two pressables. The touch event will be caught by onPress of the Icon component. This is also the reason why the navigation starts working when you remove the inner onPress function.
It seems to me that you either want setActiveLink to be triggered if we press on the Icon only or you want setActiveLink to be triggered and then navigate to the desired screen at the same time.
In the second case you just need one onPress function for the outer component.
<TouchableOpacity
key={index}
style={[
styles.menuStyle,
index === activeLink
? {backgroundColor: 'red'}
: {backgroundColor: 'white'}
]}
onPress={() => {
setActiveLink(index)
navigation.navigate(stack.route)
}}>
<Icon
name={stack.icon}
color={stack.color}
size={stack.size}
style={{
marginRight: mainMenuOpen ? '10%' : 0,
}}
/>
<Text style={{width: '70%', fontWeight: '500'}}>
{stack.label}
</Text>
</TouchableOpacity>
If you want two separate things to happen, e.g. setActiveLink on Icon press only and navigate on stack.label press only, then you need to reorganize your component. You could create a parent view which layouts the components in a row without nesting two pressables.
// you still need to apply the desired styles...
<View>
<Pressable onPress={() => setActiveLink(index)}>
<Icon
name={stack.icon}
color={stack.color}
size={stack.size}
/>
</Pressable>
<TouchableOpacity
key={index}
onPress={() => {
navigation.navigate(stack.route)
}}>
<Text style={{width: '70%', fontWeight: '500'}}>
{stack.label}
</Text>
</TouchableOpacity>
</View>

How to reference button in card component in React Native?

I'm a newbie to React/React Native, so please go easy on me. I've been stuck on this for a little while now so could use some help. Using functional React Native by the way.
How do I reference buttons that are in a card component from another screen? Using props in the card to display the toilet object's variables isn't a problem, but the buttons that are rendered through the card I can't work out how to reference them from the component with the map. Using navigation within the card doesn't work.
Screen that I want to reference the button in
{toilets.map((item, index) => {
return (
<ToiletCard
key={index}
title ={item.title}
address={item.address}
ratings={item.rating}
reviews={item.reviews}
onPress={() => {navigation.navigate("ReviewViewAndCreate", item)}}
/* I want to reference the review button using this onPress, but right now it isn't
referencing either button /*
/>
)
})}
Card component that contains the buttons
export default ToiletCard = (props) => {
return (
<View style = {styles.textContent}>
<View style = {{padding: 15}}>
<Text numberOfLine={1} style = {styles.listTitle}>{props.title}</Text>
<Text numberOfLine={1} style = {styles.listAddress}>{props.address}</Text>
<Text><StarRating ratings={props.ratings}/>{props.ratings}</Text>
<TouchableOpacity
style={styles.appButtonContainer}>
<Text style={styles.appButtonText}>Directions</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.appButtonContainerTwo}>
<Text style={styles.appButtonText}>Reviews</Text>
</TouchableOpacity>
</View>
<View style={styles.hairline}/>
</View>
)
}
Would appreciate any help.
Thanks!
Do these changes:
{toilets.map((item, index) => {
return (
<ToiletCard
key={index}
title ={item.title}
address={item.address}
ratings={item.rating}
reviews={item.reviews}
item={item}
navigation={navigation}
/* pass item as prop to this component /*
/>
)
})}
ToiletCard component:
export default ToiletCard = (props) => {
return (
<View style = {styles.textContent}>
<View style = {{padding: 15}}>
<Text numberOfLine={1} style = {styles.listTitle}>{props.title}</Text>
<Text numberOfLine={1} style = {styles.listAddress}>{props.address}</Text>
<Text><StarRating ratings={props.ratings}/>{props.ratings}</Text>
<TouchableOpacity
style={styles.appButtonContainer}>
<Text style={styles.appButtonText}>Directions</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {props.navigation.navigate("ReviewViewAndCreate", props.item)}}
style={styles.appButtonContainerTwo}>
<Text style={styles.appButtonText}>Reviews</Text>
</TouchableOpacity>
</View>
<View style={styles.hairline}/>
</View>
)
}

React Native TextInput Value persist when Tab is changed

I have encountered a weird issue in the newest react native where the value in the text input in a component remains when a tab is switched.
I can't figure what is going on and I thought it should re-render when tab is changed but it doesn't.
Here's my code
app.js
export default function App() {
const [tab, setTab] = useState("TAB1")
return (
<View style={styles.container}>
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity
style={{ borderRadius: 5, borderWidth: 1, marginRight: 5, padding: 20 }}
onPress={() => setTab("TAB1")}
>
<Text>Tab 1</Text>
</TouchableOpacity>
<TouchableOpacity
style={{ borderRadius: 5, borderWidth: 1, padding: 20}}
onPress={() => setTab("TAB2")}
>
<Text>Tab 2</Text>
</TouchableOpacity>
</View>
<View style={{ marginTop: 20}}>
{
tab === "TAB1" ? (
<View>
<InputComponent tab={tab} />
</View>
) : (
<View>
<InputComponent tab={tab} />
</View>
)
}
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
marginTop: 100,
padding: 10
},
});
inputcomponent.js
export function InputComponent({ tab }) {
const [value, setValue] = useState("");
return (
<View>
<Text>{tab}</Text>
<TextInput placeholder="INPUT HERE" value={value} onChangeText={setValue}/>
</View>
)
}
It seems like the input component re-renders but the text input within it doesn't change.
Demo Issue
This is such a good question. This is because we are importing it once and passing it to two different components. It changes the tab but uses the same textinput state because they are using the same key.
To fix this pass in the key prop so React knows that tab changed:
{
tab === "TAB1" ? (
<View>
<InputComponent key={1} tab={tab} />
</View>
) : (
<View>
<InputComponent key={2} tab={tab} />
</View>
)
}
Snack: https://snack.expo.io/mVVLb9uId
Read about keys: https://reactjs.org/docs/lists-and-keys.html#keys

Automatically scroll ScrollView in KeyboardAvoidingView when I add a new TextInput

I am working with a KeyboardAvoidingView and it's working perfectly fine except for one small issue. In the code below I have a TouchableOpacity that when clicked runs the function addName() which appends to an array and creates a new TextInput - basically when you click it, it adds a new TextInput to the ScrollView.
The KeyboardAvoidingView works perfectly fine except every time a new TextInput is added/rendered, I have to scroll down to see it. Do you know how I can make it automatically scroll to the bottom when a new TextInput is rendered?
Here is my code for the KeyboardAvoidingView:
<KeyboardAvoidingView
style={styles.container}
behavior={Platform.OS == "ios" ? "padding" : "height"}
>
<HeaderComponent
name={this.props.route.params.bill.barName + " Tab"}
navigation={this.props.navigation}
goHome={true}
goHomePrompt={true}
/>
<View
style={{
marginTop: 30,
marginLeft: 10,
}}
>
<Text
style={{ color: "white", fontSize: 18 }}
allowFontScaling={false}
>
Add people to split with...
</Text>
</View>
<ScrollView keyboardShouldPersistTaps={"handled"}>
{this.state.nameInput.map((value, index) => (
<View style={styles.nameContainer} key={index}>
<View
style={{
width: "90%",
}}
>
<TextInput
style={styles.textInputContainer}
value={value}
onChange={this.handleText(index)}
placeholder={"Enter name..."}
placeholderTextColor={"#333333"}
maxLength={50}
/>
</View>
<View
style={{
width: "10%",
}}
>
<TouchableOpacity
onPress={() => this.handleDelete(index)}
>
<Icon name="cancel" type="material" color="red" />
</TouchableOpacity>
</View>
</View>
))}
<TouchableOpacity onPress={() => this.addName()}>
<Text style={styles.addPerson}>+ Add Person</Text>
</TouchableOpacity>
</ScrollView>
<View style={styles.bottomContainer}>
<TouchableOpacity
style={styles.continueButton}
onPress={() => {
// filters through array to make sure there are no empty strings
let nameInput = this.state.nameInput.filter(
(name) => name !== ""
);
if (
nameInput.length > 1 &&
new Set(nameInput).size === nameInput.length
) {
this.setState({ nameInput, loading: false });
} else {
alert(
"Please make sure there are at least two people and no duplicate names!"
);
}
}}
>
<Text style={styles.continueButtonText} allowFontScaling={false}>
Continue to Split Tab
</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
And here is my code for the addName() function:
addName = () => {
let nameInput = this.state.nameInput.concat("");
this.setState({
nameInput,
});
};
This page has the solution I was looking for: Is it possible to keep a ScrollView scrolled to the bottom?

React native specific style item in map

I have this code that generates buttons for size as come from API like (al, l, m, s ... ) and I need to put a specific style when user click in one circle, I have tried this code but it makes the same style for all circles and I need to change the style for one circle when clicked on it :
<View style={{ paddingTop: 10, width: "49%" }}>
<View style={styles.sizeView}>
<View style={styles.sizeView3}>
<Text style={styles.chartText}>{t("size")}</Text>
</View>
</View>
<View style={styles.sizeButtons}>
{this.state.productsList[0].sizes.map((item, index) => {
return (
<TouchableOpacity
key={index}
onPress={() => this.toggle1(item)}
style={
!this.state.pressStatus
? styles.sizes
: styles.sizesAlt
}
onHideUnderlay={this._onHideUnderlay.bind(this)}
onShowUnderlay={this._onShowUnderlay.bind(this)}
>
<Text
key={index}
style={
!this.state.toggle1 ? {} : { color: "#EC1C24" }
}
>
{item}
</Text>
</TouchableOpacity>
);
})}
</View>
</View>
I drag pic for the result
The issue is that you are using one variable to change the toggle status for all the buttons (this.state.toggle1), so if one is toggle they will all be toggled, as i don't think this is the intended behavior.
I suggest to create a pure component for the buttons so that each will have it's own state and handle the toggle independetly.
as for the style, they are 2 syntax working :
style={ !this.state.toggle ? {} : { color: "#EC1C24", backgroundColor: 'red' }}
or
style={[ this.state.toggle && {color: "#EC1C24", backgroundColor: 'red'} ]}
So first create a component for the circle button
export class CircleButton extends Component {
constructor(props) {
super(props);
this.state = {
toggled: false
};
}
render() {
return (
<TouchableOpacity
key={index}
onPress={() => this.toggle1(item)}
style={
!this.state.pressStatus
? styles.sizes
: styles.sizesAlt
}
onHideUnderlay={this.props.onHideUnderlay.bind(this)}
onShowUnderlay={this.props.onShowUnderlay.bind(this)}
>
<Text
key={index}
style={
!this.state.toggle ? {} : { color: "#EC1C24" }
}
>
{item}
</Text>
</TouchableOpacity>
);
}
}
And Change your View to something like this
<View style={{ paddingTop: 10, width: "49%" }}>
<View style={styles.sizeView}>
<View style={styles.sizeView3}>
<Text style={styles.chartText}>{t("size")}</Text>
</View>
</View>
<View style={styles.sizeButtons}>
{this.state.productsList[0].sizes.map((item, index) => {
return (
<CircleButton
onHideUnderlay={this._onHideUnderlay.bind(this)}
onShowUnderlay={this._onShowUnderlay.bind(this)}/>
);
})}
</View>
</View>

Categories

Resources