If Statement in React Native - javascript

I'm having issues writing an If statement in React Native.
I'm building the mobile version of my React Js project where I already have the "if" statement but I'm not being able to write it in Native.
Here is what I got so far:
{renderItems && (
<FlatList
data={data}
keyExtractor={(item)=>{return item.date}}
numColumns={numberOfCols}
renderItem={({item})=>(
#######################################
if (item.copyright "exists" return (
<Image source(require(a specific local image)/>
else( return the code below
#######################################
<View style={styles.viewpic}>
<TouchableOpacity onPress={() => navigation.navigate('ImageDetails',
item)}>
<Image
style={{
height: 104,
width: square - 20,
margin: 10,
borderWidth: 1,
borderColor:'white',
borderRadius:2,
}}
source={{uri:item.url}}/>
</TouchableOpacity>
</View>
)}
/>)
}
the code works fine without the if part. I tried a few combos with "{" ,"(" ,"({" but nothing worked.
Thanks everyone for your help!
Cheers,

here
{renderItems &&
<FlatList
data={data}
keyExtractor={(item)=>{return item.date}}
numColumns={numberOfCols}
renderItem={({item})=>(
item.copyright== "exists" ?
<Image source(require(a specific local image)/>
:<View style={styles.viewpic}>
<TouchableOpacity onPress={() => navigation.navigate('ImageDetails', item)}>
<Image style={{
height: 104,
width: square - 20,
margin: 10,
borderWidth: 1,
borderColor:'white',
borderRadius:2,
}}
source={{uri:item.url}}/>
</TouchableOpacity>
</View>)}
/>
}

Yes, there seem to be some missing brackets. I would create a separate function like check() for the if statements and let it return the JSX elements instead:
const check = (item) => {
if (item.copyright === "exists") {
return (
<Image source={require('a specific local image')}/>
)
}
else {
return (
<View style={styles.viewpic}>
<TouchableOpacity onPress={() => navigation.navigate('ImageDetails', item)}>
<Image style={{
height: 104,
width: square - 20,
margin: 10,
borderWidth: 1,
borderColor:'white',
borderRadius:2,
}}
source={{uri:item.url}}
/>
</TouchableOpacity>
</View>
)
}
}
{renderItems && (
<FlatList
data={data}
keyExtractor={(item)=>{return item.date}}
numColumns={numberOfCols}
renderItem={({item})=>(
check(item)
)}
/>
)}
If you do not want a separate function you have to write the function in the Flatlist's renderItem a little bit different:
<FlatList
data={data}
keyExtractor={(item)=>{return item.date}}
numColumns={numberOfCols}
renderItem={({item})=> {
if (item.copyright === "exists") {
return (
<Component1/>
)
}
else {
return (
<Component2/>
)
}
}
}
/>
But still check for the brackets. They should all be correct in the first code snippet though.

Related

How to change change and track boolean state of each element in an array

Im trying to make it so that when a TouchableHighlight is pressed in react native it goes from one colour to another. I have state that is set to false and changes when the button is pressed. However this changes the colour for all elements in the map rather than for each item individually. Is there a way to update the state for each element independently?
Here is my code:
function OnboardingVibes() {
const [pressed, setPressed] = useState(false);
return (
<View style={{marginTop: 40}}>
<Text style={{fontSize: 22, color: '#FFF', marginBottom: 16}}>Vibes</Text>
<View style={styles.buttonContainer}>
{vibes.map((vibe) => {
return (
<TouchableHighlight onPress={() => setPressed(true)} style={{backgroundColor: pressed ? '#DDD' : '#4D2C5B', margin: 4, borderRadius: 4}} key={`vibe-${vibe}`}>
<Text style={styles.vibeButton}>{vibe}</Text>
</TouchableHighlight>
)
})}
</View>
</View>
);
}
One way to do it is to move the state down so you could have individual states. When the state is true at the top-level, all child components will receive the same state.
function TouchableVibe({vibe}) {
const [pressed, setPressed] = useState(false);
return (
<TouchableHighlight
onPress={() => setPressed(true)}
style={{
backgroundColor: pressed ? "#DDD" : "#4D2C5B",
margin: 4,
borderRadius: 4,
}}
>
<Text style={styles.vibeButton}>{vibe}</Text>
</TouchableHighlight>
);
}
function OnboardingVibes() {
return (
<View style={{ marginTop: 40 }}>
<Text style={{ fontSize: 22, color: "#FFF", marginBottom: 16 }}>
Vibes
</Text>
<View style={styles.buttonContainer}>
{vibes.map((vibe) => (
<TouchableVibe key={`vibe-${vibe}`} vibe={vibe} />
))}
</View>
</View>
);
}
const [pressed, setPressed] = useState(vibes.map(e=>false));
{vibes.map((vibe, index) => {
return (
<TouchableHighlight onPress={() => {
let new_Pressed =vibes.map(e=>false)
new_pressed[index]=true;
setPressed(new_pressed);
}}
style={{backgroundColor: pressed[index]
? '#DDD'
: '#4D2C5B',
margin: 4, borderRadius: 4}} key={`vibe-${vibe}`}>
<Text style={styles.vibeButton}>{vibe}</Text>
</TouchableHighlight>
)
})}
Instead of passing in a boolean to the state, pass in the id/vibe instead, and then in your conditional logic within the map you can determine if that single item is the same as the one you've clicked.
function OnboardingVibes() {
const [pressed, setPressed] = useState('');
return (
<View style={{marginTop: 40}}>
<Text style={{fontSize: 22, color: '#FFF', marginBottom: 16}}>Vibes</Text>
<View style={styles.buttonContainer}>
{vibes.map((vibe) => {
return (
<TouchableHighlight onPress={() => setPressed(vibe)} style={{backgroundColor: pressed === vibe ? '#DDD' : '#4D2C5B', margin: 4, borderRadius: 4}} key={`vibe-${vibe}`}>
<Text style={styles.vibeButton}>{vibe}</Text>
</TouchableHighlight>
)
})}
</View>
</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

React Native, Calling a Function from Another one in Render

I have this SMN() function and I've created inside it Site function as Const. So I need to call Site function in Render() function. This is main function code:
SMN() {
const Site = () => {
return (
<View style={{ height: 400 }}>
<WebView source={{ uri: 'https://www.google.com' }} style={{ marginTop: 20 }} />
</View>
);
}
});
This is Render() function where I want to call Site function from it, I've used:
this.SMN().Site , this does not throw errors but does not display any.
render() {
return (
</View>
<View>{this.SMN().Site}</View>
</View>
)
}
Make your Site as a component just like this:
const Site = () => {
return (
<View style={{ height: 400 }}>
<WebView
source={{ uri: 'https://www.google.com' }}
style={{ marginTop: 20 }} />
</View>
);
}
And in your render function use it like this:
render() {
return (
</View>
<View><Site /></View>
</View>
)
}
I think you want to get the return you want from SMN(). So this is what I thought your intended solution was.
SMN() {
return (
{
Site : () => (
<View style={{ height: 400 }}>
<WebView source={{ uri: 'https://www.google.com' }}
style={{marginTop:20 }} />
</View>
)
}
);
});
render() {
return (
</View>
<View>{this.SMN().Site}</View>
</View>
)
}

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?

Not able to access the absolute position view in react-native android

I have a component called MDropDowlList which render the following view :
MDropDownList.js
render() {
return (
<View>
<View
style={{
backgroundColor: '#fff',
position: 'absolute',
left: 0,
right: 0,
top: 0,
maxHeight: 200,
}}
>
{
this.props.searchable && (
<TextInput
style={{ zIndex: 198 }}
onChangeText={(text) => this.search(text)}
/>
)
}
<FlatList
data={this.state.data}
keyboardShouldPersistTaps="always"
nestedScrollEnabled={true}
contentContainerStyle={{ zIndex: 199 }}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item, index }) => (
<TouchableHighlight
key={index.toString()}
style={{
padding: 10,
backgroundColor: '#fff',
}}
underlayColor="#5897fb"
onPress={() => this.props.handleOnPress(item)}
>
<MText size={18}>{item}</MText>
</TouchableHighlight>
)}
/>
</View>
</View>
);
}
Then I have called this component to another component called MDropDown which render method is as below :
MDropDown.js
render() {
return (
<View style={{ marginVertical: 5, zIndex: 3}}>
...
{/* Another components */}
...
{
this.state.displayDropDown && (
<MDropDownList data={this.props.data} searchable={this.props.searchable} handleOnPress={(item) => this.handleOnPress(item)} />
)
}
</View>
);
}
Now finally I called my MDropDown component in my main screen as follow :
render() {
return (
<KeyboardAvoidingView style={{ flex: 1, backgroundColor: Colors.bgGray }} behavior="padding">
<ScrollView showsVerticalScrollIndicator={false} contentContainerStyle={styles.container} keyboardShouldPersistTaps="always" nestedScrollEnabled={true}>
<View style={{ backgroundColor: '#fff', padding: 10 }}>
<MDropDown
label="Category"
placeholder="Select Category"
data={["test1", "test2", "test3", "test4", "test5"]}
onSelectItem={(selectedItem) => alert(selectedItem)}
searchable={true}
/>
</View>
</ScrollView>
</KeyboardAvoidingView>
)
}
But I am not able to access Flatlist item or TextInput of MDropDownList component. Even I am not able to focus TextInput available in MDropDownList.
Please help me what's going wrong here ???
Note : This issue is only on android, on ios it is working properly. On ios I am able to click flatlist item and focus TextInput as well as.
Tried using zIndex to the absolute view?
Add property of zIndex : 500 to the style.

Categories

Resources