react native- how to add items separately when item is onpressed - react-native

I have been able to add item in onPress but it only shows the pressed item only. I want it to displays all the selected item in a row in the view beneath.
const [text, setText] = useState([]);
const numbers =['1','2','4', '5', '6', '7', '8', '9', '10','11','12','13','14','15','16','17','18','19']
const onPress =(item)=>{
setText(<Text style={{textAlign:"center"}}>{item});
console.log(item)
};
return (
<View style={styles.container}>
<ScrollView>
<View style={{flexDirection: 'row',flexWrap: 'wrap', justifyContent:"center"}}>
{numbers.map((item, index) => {
return (
<TouchableOpacity style={styles.item} onPress={()=>onPress(item)}>
<Text style={{textAlign:"center"}} key={index}> {item}</Text>
</TouchableOpacity>
)})}
</View>
<View style={styles.select}>{text}</View>
</ScrollView>
</View>
)
}
enter image description here

The problem with your current code is that your onPress will override the previous value instead of appending to it. To append previous values into your text, you will need to first destructure the text state in your onPress followed by the new number.
const onPress = (item) => setText(oldText => {
if (oldText.length < max) {
return [...oldText, item]
} else return oldText
})

Related

How to use hooks as image's source in react native?

Im making this menu that when the user clicks at an option, it changes the background image, but i cant use the hook that i created as a parameter to the source of the image. Can someone find where im wrong and how to fix it?
Heres the part of my code referents to the menu and the hooks:
export function Home(){
let imagens = {
vovo: '../assets/vovoJuju.png',
mc: '../assets/mcJuju.png',
pato: '../assets/patoJuju.png',
}
const navigation = useNavigation<any>();
const [showBottomSheet, setShowBottomSheet] = React.useState(false);
const [param, setParam] = useState(1);
const [skin, setSkin] = useState('vovo')
const hide = () => {
setShowBottomSheet(false)
}
function handleAbout(){
navigation.navigate('About');
}
useEffect(() => {
if(param==1){
setSkin('vovo');
}
else if(param==2){
setSkin('mc');
}
else if(param==3){
setSkin('pato');
}
})
return(
<SafeAreaView style={styles.container}>
<TouchableOpacity onPress={handleAbout}>
<Counter />
</TouchableOpacity>
<TouchableOpacity onPress={() => {
setShowBottomSheet(true)
}}
>
<Image source={skin} style={styles.imgvj}/>
</TouchableOpacity>
<BottomSheet show={showBottomSheet} height={290} onOuterClick={hide}>
<Pressable onPress={hide} style={styles.bottomSheetContent}>
<Image source={barrinhaLoja} style={styles.barra}/>
</Pressable>
<View style={styles.conteudoLoja}>
<View style={styles.marginLeft48}>
<TouchableOpacity onPress={() => {
setParam(1);
}}>
<Image source={vovoJuju} style={styles.vovo}/>
<Text style={styles.legendasLoja}>Vovó Juju</Text>
</TouchableOpacity>
</View>
<View>
<TouchableOpacity onPress={() => {
setParam(2);
}}>
<Image source={mcJuju} style={styles.mc}/>
<Text style={styles.legendasLoja}>MC Juju</Text>
</TouchableOpacity>
</View>
<View>
<TouchableOpacity onPress={() => {
setParam(3);
}}>
<Image source={patoJuju} style={styles.pato}/>
<Text style={styles.legendasLoja}>Pato Juju</Text>
</TouchableOpacity>
</View>
</View>
</BottomSheet>
I created the "let imagens", "const param", "const skin" and the "useEffect trying" to make this function. I already tried using the source in different ways such as source={skin} and source={imagens[skin]} but it havent worked.
I'm not certain if this solves your problem, but here's how the first few lines of your component should look like without useEffect:
const imagens = {
vovo: '../assets/vovoJuju.png',
mc: '../assets/mcJuju.png',
pato: '../assets/patoJuju.png',
};
export function Home(){
const navigation = useNavigation<any>();
const [showBottomSheet, setShowBottomSheet] = React.useState(false);
const [param, setParam] = useState(1);
const hide = () => {
setShowBottomSheet(false)
}
function handleAbout(){
navigation.navigate('About');
}
let skin = 'vovo';
switch(param) {
case 1: skin = 'vovo'; break;
case 2: skin = 'mc'; break;
case 3: skin = 'pato'; break;
}
return /* the rest goes here */
}
To reference the actual image, you would use something like {imagens[skin]}.
I moved imagens outside of this function because it never changes, but it doesn't impact anything otherwise.

React native list map() method add custom element below selected Item

When Item with id=1 selected
then the element appear below
the selected Item. And when
unselected the element disappear.
This is a list with map() method.
The element should be inside the
SrollView like Item
But isn’t a new Item
I have this code that can create a new Item below the selected Item but I don't want to create a new Item but only appear a custom View(element) like above.
Expo Snack> https://snack.expo.dev/#stefanosalexandrou/honest-cashew
You could store the selected index in a state, which you are already doing. Then, use conditional rendering in order to render a custom component below the selected item. Furthermore, if a selected item is pressed again, set the state to undefined.
The handleOnPress function.
function handleOnPress(idx) {
setSelectedId(prev => prev === idx ? undefined : idx)
}
The updated render function.
<View style={styles.container}>
<ScrollView>
<View>
{data.map((person, index) => {
const backgroundColor = index === selectedId ? "#6e3b6e" : "#f9c2ff";
return (
<View>
<TouchableOpacity
onPress={() => handleOnPress(index)}
style={{
padding:20,
backgroundColor: backgroundColor,
marginBottom:20,
}}
>
<Text>{person.name}</Text>
</TouchableOpacity>
{
index === selectedId ? <View style={{backgroundColor: "red", height: 100, width: "100%"}}><Text>Custom Super Component Visible on press of above item </Text></View> : null
}
</View>
);
})}
</View>
</ScrollView>
</View>
I have added a dummy component if the index is selected.
However, you might want to select multiple items one after the other and deselect them individually while having the same effect. For doing so, we change the state to store an array of indices instead.
The updated state and handleOnPress function.
const [selectedIndices, setSelectedIds] = useState([]);
function handleOnPress(idx) {
if (selectedIndices.includes(idx)) {
setSelectedIds(prev => prev.filter(i => i !== idx))
} else {
setSelectedIds(prev => [...prev, idx])
}
}
The updated render function.
return (
<View style={styles.container}>
<ScrollView>
<View>
{data.map((person, index) => {
const backgroundColor = selectedIndices.includes(index) ? "#6e3b6e" : "#f9c2ff";
return (
<View>
<TouchableOpacity
onPress={() => handleOnPress(index)}
style={{
padding:20,
backgroundColor: backgroundColor,
marginBottom:20,
}}
>
<Text>{person.name}</Text>
</TouchableOpacity>
{
selectedIndices.includes(index) ? <View style={{backgroundColor: "red", height: 100, width: "100%"}}><Text>Custom Super Component Visible on press of above item </Text></View> : null
}
</View>
);
})}
</View>
</ScrollView>
</View>
);

React-Native how to show different API by same id in Flatlist

i have two different API and i want show two API in one Flatlist this is worked (look the picture). i show it using filter by id API (if API have same id will show). My question is how to remove/hide/dont show null value flatlist (look the picture)?
Im using API from https://jsonplaceholder.typicode.com
picture my app
const {user, post} = useSelector(state => state.reducer);
const dispatch = useDispatch();
const getData = [...user, ...post];
useEffect(() => {
dispatch(getProfile());
dispatch(getPost());
}, []);
const tailwind = useTailwind();
const renderPost = ({item}) => {
const renUsr = user.filter(renUsr => renUsr.id === item.userId);
return (
renUsr.id !== item.userId ? (
<View style={tailwind('pb-4')}>
<View style={tailwind('px-4 py-4 bg-gray-200 mx-6 rounded-[20px]')}>
<View style={tailwind('flex flex-row')}>
<Image style={tailwind('rounded bg-black w-8 h-8')} />
{renUsr.map(posting => (
<Text
key={posting.id}
style={tailwind('pl-2 font-semibold py-2')}>
{posting.name}
</Text>
))}
</View>
<View style={tailwind('mt-2')}>
<TouchableHighlight
style={styles.touchHighlight}
onPress={navigation}>
<View style={tailwind('bg-gray-200 p-1')}>
<Text key={item.id}>{item.body}</Text>
</View>
</TouchableHighlight>
</View>
</View>
</View>
) : (
null
)
);
};
return (
<FlatList
data={getData}
renderItem={renderPost}
keyExtractor={item => item.id}
/>
);
};
user.filter(renUsr => renUsr.id === item.userId);
Instead of using the filter here, just filter the list passed to the flatlist so you it will be looped only once and you don't to filter for every single item

Is there a way to get the Title of the selected item from another component in React Native

I have two different components "HomePage" & "ListItemCA"
In HomePage, I have a FlatList and a modal popup
<FlatList
data={ listData}
keyExtractor={list => list.Title}
renderItem={({ item }) => <ListItemCA data={item} onLongPress={openModal} />}
/>
and each list item is called from another component ListItemCA
function ListItemCA({data, onLongPress}) {
return (
<TouchableOpacity onLongPress={onLongPress} >
<View style={styles.container}>
<Text style={styles.title}>{data.Title}</Text>
<View style={styles.metaContainer}>
<Text style={styles.meta}>{( data.totalMonths != null ? data.totalMonths : '0' )} Months</Text>
<Text style={styles.meta}>{( data.members != null ? data.members.length : '0' )} Members</Text>
</View>
</View>
</TouchableOpacity>
);
}
What I want to acheive?
I want to get the selected list item title on my HomePage component. When a user longpress on a list item that title should be displayed on a modal popup. How do I pass the selected list item title to the HomePage component using longpress?
If your goal is to display data from the long pressed item in the modal, you could add the data as a parameter of your openModal function:
function openModal(data) {
// your function
return (
<Text>{data.Title}</Text>
)
}
Then, in your FlatList, modify the props of ListItemCA to call openModal for the selected item:
renderItem={({ item }) => <ListItemCA data={item} onLongPress={openModal(item)} />}
If you also want to save the data from the long pressed item in your HomePage component for other uses, you could save it in the state. In your HomePage component:
import React, { useState } from 'react'
function HomePage() {
const [itemData, setItemData] = useState()
// your code
}
Then, in your flatlist:
<FlatList
data={listData}
keyExtractor={list => list.Title}
renderItem={({ item }) =>
<ListItemCA
data={item}
onLongPress={ () => {
setItemData(item)
openModal(item)
}}
/>
}
/>
You can achieve this by passing(return) parameter from your component like this -
function ListItemCA({data, onLongPress}) {
return (
<TouchableOpacity onLongPress={() => {
onLongPress(data.Title);
//return data.Title when onLongPressed clicked
}}>
<View style={styles.container}>
...
</View>
</TouchableOpacity>
);
}
then get it in props -
<FlatList
data={listData}
keyExtractor={list => list.Title}
renderItem={({ item }) =>
<ListItemCA
data={item}
onLongPress={(title) => {//this **title** return from **onLongPress(data.Title)**
openModal();
setTitle(title);// or directly can pass that title in openModal func.
}}
/>
}
/>

Increase Parent Flatlist Item Height w.r.t child flatlist in Nested flatlist in React Native

I'm trying to create a nested Flatlist(Flatlist inside another Flatlist), with dynamic data that is fetched from webservices.
Once the inner flatlist data gets fetched, basing on the content I am trying to increase the parent flatlist item height.
Can somebody guide me to solve the problem
The below is the view I am working
From App.js
renderItem = ({ item }) => {
if (item.empty === true) {
return <View style={[styles.item, styles.itemInvisible]} />;
}
return (
<View style={styles.item}>
<Text style={styles.itemText}>Name</Text>
<Text style={styles.itemText}>{item.key}</Text>
<InnerListView updateHeight={this.updateHeight} />
</View>
);
};
render() {
return (
<FlatList
data={[
{ key: 'ABCDEFGH' }
]}
style={styles.container}
renderItem={this.renderItem}
numColumns={numColumns}
/>
);
}
From InnerList
find_dimesions(layout){
const {x, y, width, height} = layout;
console.warn("xpos"+ x);
console.warn("ypos"+y);
console.warn("width"+width);
console.warn("height"+height);
this.props.updateHeight(height)
}
renderItem = ({ item, index }) => {
if (item.empty === true) {
return (<View style={[styles.item, styles.itemInvisible]} />);
}
return (
<View style={styles.item}>
<Text style={styles.itemText}>Name</Text>
<Text style={styles.itemText}>{item.key}</Text>
</View>
);
};
render() {
return (
<FlatList
onLayout={(event) => { this.find_dimesions(event.nativeEvent.layout) }}
data={formatData(data, numColumns)}
style={styles.container}
renderItem={this.renderItem}
numColumns={numColumns}
/>
);
}
I am expecting the parent view i.e redView height need to be increased.
First of all, an FYI: you could create this exact layout with a single SectionList as well if you want.
But to answer your question to get the outer flatlist to update its content / layout when the inner gets updated, you could make use of the extraData prop from FlatList. This prop allows the FlatList to update once its value changes. So the extraData you provide to the outer FlatList should be the same as the data for the inner FlatList.