React Native conditional rendering not working - react-native

I want to have a side menu, with a list of categories and when the user selects a category, it should open a scrollable list, right below the category name, with all the pieces of that category.
So I created two list components, one for the categories (SideMenuList) and one for the furniture pieces. I figured I needed to use conditional rendering to render the second list when the user selects the category.
My code:
Side menu code from app.js
state = {
hideMenu: null,
hideList: null
}
sideMenuShow() {
if(!this.state.hideMenu) {
return(
<SideMenu>
<MenuButton onPress = {() => this.setState({hideMenu: true})}/>
<Text style = {{color: 'white', fontSize: 16, fontWeight: 'bold'}}>Furniture</Text>
<SideMenuList onPress = {() => this.setState({hideList: true})}>
{
this.state.hideList ? console.log('yes') : null
}
</SideMenuList>
</SideMenu>
);
}
else {
return(
<SmallSideMenu>
<MenuButton onPress = {() => this.setState({hideMenu: false})}/>
</SmallSideMenu>
);
}
}
SideMenuList.js
import React, { Component } from 'react';
import { View, FlatList, Text, TouchableOpacity } from 'react-native';
import { CardSection } from './common';
import SideMenuItem from './SideMenuItem';
class SideMenuList extends Component {
render() {
return (
<View style = {{flex: 1}}>
<FlatList
style = {{marginBottom: 2}}
data={[
{key: 'Test'},
{key: 'Test2'},
{key: 'Test3'},
{key: 'Test4'},
{key: 'Test5'}
]}
renderItem={({item}) =>
<TouchableOpacity>
<SideMenuItem
onPress = {this.props.onPress}
text={item.key}
>
{this.props.children}
</SideMenuItem>
</TouchableOpacity>}
/>
</View>
);
}
}
export default SideMenuList;
SideMenuItem.js code
import React from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
const SideMenuItem = (props, {onPress}) => {
return (
<View
style = {{flex: 1}}>
<TouchableOpacity
onPress = {onPress}>
<Text style={styles.itemStyle}>{props.text}</Text>
</TouchableOpacity>
{props.children}
</View>
);
}
const styles = {
itemStyle: {
marginTop: 10,
marginRight: 20,
marginLeft: 10,
color: 'white'
}
};
export default SideMenuItem;
My problem right now is that my onPress event is not changing the value of my state property 'hideList', so I can't even check if my solution would actually work. I'm doing a console log when the value is true but it never appears in my console.
Thanks in advance.

You are rendering your SideMenuItem with a TouchableOpacity wrapping it (in your SideMenuList file).
Probably when you are pressing the button, it's triggering SideMenuList button, instead of SideMenuItem button.
Try to remove the TouchableOpacity from SideMenuList and check if it works.
Hope it helps

Related

Expo / TouchableOpacity onPress() not responding

I'm trying to reproduce a pomodoro app from an online course.
I've been looking at my code for several hours, going back and forth with the course, but can't find my error.
TouchableOpacity or Pressable used in RoundedButton component doesn't trigger onPress()
I tried different command to test if my logic with setStarted was flawe, without success.
Anyone can help me find my bug ?
Here is the link to the expo : https://snack.expo.dev/#battlepoap/focus-time
RoundedButton.js:
import React from 'react';
import { TouchableOpacity, Text, StyleSheet, View } from 'react-native';
export const RoundedButton = ({
style = {},
textStyle = {},
size = 125,
...props
}) => {
return (
<View>
<TouchableOpacity style={[styles(size).radius, style]}>
<Text style={[styles(size).text, textStyle]}>{props.title}</Text>
</TouchableOpacity>
</View>
);
};
const styles = (size) =>
StyleSheet.create({...});
Example with Focus.js where we add a task by pressing on the RoundedButton :
import React, { useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { TextInput } from 'react-native-paper';
import { RoundedButton } from '../../components/RoundedButton';
import { fontSizes, spacing } from '../../utils/sizes';
export const Focus = ({ addSubject }) => {
const [tempSubject, setTempSubject] = useState(null);
return (
<View style={styles.container}>
<View style={styles.titleContainer}>
<Text style={styles.title}>What do you want to focus on ?</Text>
<View style={styles.inputContainer}>
<TextInput
style={{ flex: 1, marginRight: spacing.sm }}
onSubmitEditing={({ nativeEvent }) => {
setTempSubject(nativeEvent.text);
}}
/>
<RoundedButton
size={50}
title="+"
onPress={() => addSubject = tempSubject}
/>
</View>
</View>
</View>
);
};
sic In the additional files there was ....
One thing we however need to add in order to make sure the button triggers is the onPress method. This method allows us to trigger the touch event of the user. Don't forget it!!
<TouchableOpacity style={[styles(size).radius, style]}>
<Text
style={[styles(size).text, textStyle]}
onPress={props.onPress}>
{props.title}
</Text>
</TouchableOpacity>

React Native ,Flatlist : how to remove 'unread' note ,once you cliked

I am making a function ,which is at the begining ,all the message are 'unread' .. And once you click the message ,the unread will disappear .like the example as follow:
I had made a component Card.js :
import React from 'react';
import { Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
function Card({
img,
userType,
visible,
onPress,
}) {
return (
<TouchableOpacity style={styles.container} onPress={onPress}>
<View style={styles.container}>
<Image style={styles.img} source={img}/>
{/** userType: 0:teacher 1:student 2.other */}
{userType===0&&(
<Text style={styles.txt}>teacher</Text>
)}
{userType===1&&(
<Text style={styles.txt}>student</Text>
)}
{userType===2&&(
<Text style={styles.txt}>other</Text>
)}
{visible===1&&(
<Text style={styles.txt_notice}>Unread</Text>
)}
</View>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
container : {
width : '90%',
flexDirection : 'row',
justifyContent :'center',
alignItems : 'center',
marginTop : 10,
},
txt : {
fontSize : 18,
marginLeft : 20,
},
img : {
width :100,
height : 100,
borderRadius : 50,
},
txt_notice :{
fontSize : 16,
color :'#DC143C',
marginLeft :10,
}
})
export default Card;
and the screen i used TryScreen.js:
import React, { useState,useEffect } from 'react';
import { FlatList, StyleSheet, View } from 'react-native'
import Card from '../components/Card';
const clients = [
{id:1,img:{uri:'https://i.pinimg.com/564x/64/02/cb/6402cbd3d436caecad2f3e300d67ebd1.jpg'},userType:0,visible:1},
{id:2,img:{uri:'https://i.pinimg.com/236x/34/d6/8c/34d68c7694e1c43204c0dbc623ce4cb8.jpg'},userType:1,visible:1},
{id:3,img:{uri:'https://i.pinimg.com/236x/a0/14/26/a014261951fae6dcc16b4d555f0ef089.jpg'},userType:2,visible:1},
{id:4,img:{uri:'https://i.pinimg.com/236x/96/bf/b6/96bfb641920f527e4fcc9ca23501e222.jpg'},userType:2,visible:1},
{id:5,img:{uri:'https://i.pinimg.com/236x/8b/6e/d9/8b6ed9f0cd6de175537879233a017b0c.jpg'},userType:1,visible:1},
{id:6,img:{uri:'https://i.pinimg.com/236x/0e/16/7f/0e167fab5f152a630fd80dfa1ad3e47c.jpg'},userType:0,visible:1},
]
function TyeScreen(props) {
const[clients_list,setClients]=useState([]);
useEffect(()=>{
setClients(clients);
},[]);
return (
<View style={styles.container}>
<FlatList
data = {clients}
keyExtractor = {item =>item.id.toString()}
renderItem = {({item,index})=>(<Card
img = {item.img}
userType = {item.userType}
visible = {item.visible}
onPress = {()=>{
item.visible -=1;
setClients(item);
}}
/>)}
/>
</View>
);
}
const styles = StyleSheet.create({
container : {
flex : 1,
backgroundColor : '#ffffff',
}
})
export default TyeScreen;
My idea is when click the message ,the 'unread' notice will disappear ... I have tried many ways ,but not worked ... Could you please help me take a look my code ,thank you so much !!
Your clients-list need to be in the state, something like
const [clients, setClients] = useState();
then you initialize them in
useEffect(() => {
setClients(...)
})
and then in onPress you change the property of the selected client and change the state again.
Edit
a simple implementation to force re-rendering
onPress = (client) => {
client.unread = -1;
const newclients = {...clients};
setClients(newclients);
}

React Native last child selector not working

I'm trying to use the last child selector remove the bottom border from the last Text tag here.
I've used both the EStyleSheet and the StyleSheet but it doesn't seem to be working – the last Text tag still has a bottom border.
I've wrapped the Text tags in View and applied the 'opt' style to the View instead and that also doesn't work.
What am I doing something wrong?
import React from 'react';
import EStyleSheet from 'react-native-extended-stylesheet';
import {
Text,
View,
Image,
} from 'react-native';
EStyleSheet.build()
const styles = EStyleSheet.create({
container:{
flex:1,
},
options:{
},
opt:{
padding:5,
fontSize:25,
borderWidth:1,
borderColor:'black',
},
'opt:last-child': {
borderBottomWidth:0,
}
});
const Settings = () => {
return <View style={styles.container}>
<View style={styles.options}>
<Text style={styles.opt}>Edit profile</Text>
<Text style={styles.opt}>Preferences</Text>
<Text style={styles.opt}>Account settings</Text>
</View>
</View>
};
export default Settings;
To accomplish an item-order aware styling, try something that makes use of EstyleSheet.child like this way:
const items = ['Edit profile', 'Preferences', 'Account settings'];
const Settings = () => (
<View style={styles.container}>
<View style={styles.options}>
{items.map((text, i) => {
const style = EStyleSheet.child(styles, 'opt', i, items.length);
return <Text style={style}>{text}</Text>;
})}
</View>
</View>
);

How to change state value in const mode?

I am a beginner in React-Native.
I tried to change the state value.
But it seems different with "class" mode. Now I am using "const" mode.
In const mode, how can I change the state value?
import React from "react";
import {
View,
Text,
Image,
TouchableOpacity
} from "react-native";
const Product = props => {
this.state = {
checkIconURL : require('../../assets/ic_check_circle.png')
}
set = () => {
this.setState({ checkIconURL : require('../../assets/empty.png') }) //But this lines gives err.
}
return (
<View>
<Text style={{ fontSize: 16}}>Everyday</Text>
<TouchableOpacity onPress = {this.set}>
<Image source = {this.state.checkIconURL} style={{width: 30, height: 30}} />
</TouchableOpacity>
</View>
)
}
state is not available in function components, this.state and this.setState() can only be used in class component, u have to use useState hook from react to use the state...
import React ,{ useState } from "react";
import {
View,
Text,
Image,
TouchableOpacity
} from "react-native";
const Product = props => {
const initialState = require('../../assets/ic_check_circle.png');
const [iconUrl, setIconUrl ] = useState(initialState);
const set = () => {
const emptyImageUrl = require('../../assets/empty.png')
setIconUrl(emptyImageUrl);
}
return (
<View>
<Text style={{ fontSize: 16}}>Everyday</Text>
<TouchableOpacity onPress = {set}>
<Image source = {iconUrl} style={{width:
30, height: 30}} />
</TouchableOpacity>
</View>
)
}
the following code is incorrect as you need to use Hook in a functional component to manage state.
React provides the useState hook to manage state in a functional component.
import React ,{ useState } from "react";
import {
View,
Text,
Image,
TouchableOpacity
} from "react-native";
const Product = props => {
const initialState = require('../../assets/ic_check_circle.png');
const [ state,setState ] = useState({checkIconURL: initialState});
set = () => {
const emptyImageUrl = require('../../assets/empty.png') });
setState({...state, checkIconURL: emptyImageUrl })
}
return (
<View>
<Text style={{ fontSize: 16}}>Everyday</Text>
<TouchableOpacity onPress = {this.set}>
<Image source = {this.state.checkIconURL} style={{width:
30, height: 30}} />
</TouchableOpacity>
</View>
)
}

Adding a View By Clicking a Button- REACT NATIVE

How can I add a view to the bottom of the screen with the click of a button, which is at the top of the screen, in React Native?
you make the view at the bottom of the screen conditionally render based on a state and you set it that state to be true on the OnPress method of the button
I think it is better to learn more about state and props and other fundamental concepts in react/react-native first:
https://facebook.github.io/react-vr/docs/components-props-and-state.html
but here is how you can do this:
You need to define a state if you can view that section as
false
, then when the button pressed, change the value of that state to
true
import React from 'react';
import {Text,View,TouchableOpacity} from 'react-native';
export default class testComponent extends React.Component {
constructor(){
super()
this.state = {
viewSection :false
}
}
renderBottomComponent(){
if(this.state.viewSection) {
return (
<View>
<Text>Hi!</Text>
</View>
)
}
}
buttonPress=()=>{
this.setState({viewSection:true})
}
render() {
return (
<View >
<TouchableOpacity onPress={this.buttonPress}>
<Text> Click Me!</Text>
</TouchableOpacity>
{this.renderBottomComponent()}
</View>
);
}
}
You can try this,
According to my knowledge this is what you want
import React, { useState } from 'react';
import { Button, View } from 'react-native';
export default function Testing() {
const Square = () => (
<View style={{
width: 50,
height: 50,
margin: 10,
backgroundColor: "green",
}} />
);
const [squares, setSquares] = useState([<Square />, <Square />, <Square />]);
return (
<View >
{squares.map(v => v)}
<Button title='add' onPress={() => setSquares([...squares, <Square />])} />
</View >
)
}