//I am rendering an API response with the help of FLatlist but when I press the expand option it will open all the accordions.................
import { View, Text, StyleSheet, FlatList } from 'react-native'
import React, { useState } from 'react'
import SearchBox from '../../components/SearchBox/SearchBox'
import { ListItem, Icon, Slider } from '#rneui/themed'
import { useSelector } from 'react-redux'
import { getAllPackages } from '../../feature/packageSlice'
const Rounds = () => {
const [expanded, setExpanded] = useState(false)
const pack = useSelector(getAllPackages)
//flatlist render item
const renderItem = ({ item }) => {
return (
<ListItem.Accordion
content={
<>
<ListItem.Content>
<ListItem.Title style={styles.header}>
{item.name}
</ListItem.Title>
</ListItem.Content>
</>
}
isExpanded={expanded}
onPress={() => {
setExpanded(!expanded)
}}
>
<View style={styles.card}>
<Text style={styles.font}>Water Supply Pressure</Text>
</View>
</View>
</ListItem.Accordion>
)
}
//main render
return (
<View>
<FlatList
data={pack}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
</View>
</View>
)
}
export default Rounds
I want to open up the selected accordion only how can I achieve that, please help thanks...................................................................................................................................
If i understand your code correctly and this is one component (not fraction of few) your problem is following:
const [expanded, setExpanded] = useState(false)
This state variable is on top of your parent Component, so each rendered item points to it.
Therefore if you change it from any of your ListItem.Accordion, it will affect all of them.
BUT
If you change your renderItem to render Component. like this:
const renderItem = ({ item }) => {
return (
<AccordionListItem item={item}/>
)
}
Then you can move this state inside AccordionListItem itself, so it will create unique instance for each unique instance of component.
//imports
import React from ...
const AccordionListItem = ({item}) => {
const [expanded, setExpanded] = useState(false) <========= !
return (
<ListItem.Accordion
content={
<>
<ListItem.Content>
<ListItem.Title style={styles.header}>
{item.name}
</ListItem.Title>
</ListItem.Content>
</>
}
isExpanded={expanded}
onPress={() => {
setExpanded(!expanded)
}}
>
<View style={styles.card}>
<Text style={styles.font}>Water Supply Pressure</Text>
</View>
</View>
</ListItem.Accordion>
)
}
export default AccordionListItem ;
Related
I'm pretty new to React Native and don't have the most experience with javascript so although this may be very simple I have no idea what to do. I have a class Component which acts like a popup in my app. It pops up on press of a touchable opacity and displays a little menu. I am trying to get the id of the button that is pressed on that menu and send it back to the functional component main screen (where the touchable opacity to open the menu is). I can get the id of the button but I'm struggling to get this data out of the popup and back into my main screen(functional component)
Here is my Code for the Main Screen:
import { StyleSheet, Text, View, Image,TouchableOpacity} from 'react-native'
import React,{useState} from 'react'
import tw, { create } from 'twrnc';
import Map from "../components/Map"
import { SafeAreaView } from 'react-native-safe-area-context';
import { BottomPopup } from '../components/popup';
import { selectTrucks} from '../slices/navSlice';
import { useSelector } from 'react-redux';
const Logistics = () => {
const Trucks = useSelector(selectTrucks);
let popupRef = React.createRef()
const onShowPopup = () => {
popupRef.show()
}
const onClosePopup = () => {
popupRef.close()
}
return (
<View style={{flex:1,resizeMode:'contain'}}>
<View style={tw`h-12/16`}>
<Map/>
</View>
<TouchableOpacity onPress={onShowPopup} style={{top:'-68%'}}>
<Image
source = {{uri: "https://icon-library.com/images/app-menu-icon/app-menu-icon-21.jpg" }}
style = {{width:'20%', height:40,resizeMode:'contain'}}
/>
<Text style={{color:'black',paddingLeft:2,fontSize: 26,fontWeight:"bold",top:-37,left:70}}>Truck {}</Text>
</TouchableOpacity>
<BottomPopup
title = "Select Option"
ref = {(target)=> popupRef = target}
onTouchOutside={onClosePopup}
data={Trucks.TrucksInfo}
/>
<SafeAreaView style={{top:'-13%'}}>
<Text style={{color:'darkgreen',paddingLeft:2,fontSize: 36,fontWeight:"bold"}}>123 Elmo Street</Text>
<Text style={{color:'darkgreen',paddingLeft:2,fontSize: 24,fontWeight:"bold"}}>L4L 6L8, Mississauga, Ontario</Text>
<Text style={{color:'darkgreen',paddingLeft:2,fontSize: 18,fontWeight:"bold"}}>Phone Number: 416-749-6857{'\n'}Client: Bobby Jeff{'\n'}Order Number: 7187181{'\n'}Packing Slip Number: 882929</Text>
<Text style={{color:'black',fontSize: 18,paddingLeft:2}}>Customer Notified: Yes at 2:32 PM</Text>
</SafeAreaView>
</View>
)
}
export default Logistics
const styles = StyleSheet.create({})
And Here is the code for the class component popup:
import { Modal,Dimensions,TouchableWithoutFeedback,StyleSheet,View,Text,FlatList,TouchableOpacity} from "react-native";
import React from "react";
import { useNavigation } from '#react-navigation/native';
import Logistics from "../screens/Logistics";
const deviceHeight = Dimensions.get('window').height
export class BottomPopup extends React.Component {
constructor(props){
super(props)
this.state = {
show:false
}
}
show = () => {
this.setState({show:true})
}
close = () => {
this.setState({show:false})
}
renderOutsideTouchable(onTouch) {
const view = <View style = {{flex:1,width:'100%'}}/>
if (!onTouch) return view
return (
<TouchableWithoutFeedback onPress={onTouch} style={{flex:1,width:'100%'}}>
{view}
</TouchableWithoutFeedback>
)
}
renderTitle = () => {
const {title} = this.props
return (
<View style={{alignItems:'center'}}>
<Text style={{
color:'#182E44',
fontSize:25,
fontWeight:'500',
marginTop:15,
marginBottom:30,
}}>
{title}
</Text>
</View>
)
}
renderContent = () => {
const {data} = this.props
return (
<View>
<FlatList
style = {{marginBottom:130}}
showsVerticalScrollIndicator = {false}
data={data}
renderItem={this.renderItem}
extraData={data}
keyExtractor={(item,index)=>index.toString()}
ItemSeparatorComponent={this.renderSeparator}
contentContainerStyle={{
paddingBottom:40
}}
/>
</View>
)
}
renderItem = ({item}) => {
return(
<TouchableOpacity
onPress={() => {this.close(),console.log(item.id)}}
>
<View style = {{height:50,flex:1,alignItems:'flex-start',justifyContent:'center',marginLeft:20}}>
<Text style={{fontSize:18,fontWeight:'normal',color:"#182E44"}}>{item.name}</Text>
</View>
</TouchableOpacity>
)
}
renderSeparator = () => {
return(
<View
style={{
opacity:0.1,
backgroundColor:'#182E44',
height:1
}}
/>
)
}
render() {
let {show} = this.state
const {onTouchOutside,title} = this.props
return (
<Modal
animationType={"fade"}
transparent={true}
visible={show}
onRequestClose={this.close}
>
<View style={{flex:1, backgroundColor:"#000000AA",justifyContent:'flex-end'}}>
{this.renderOutsideTouchable(onTouchOutside)}
<View style={{
backgroundColor:'#FFFFFF',
width:'100%',
paddingHorizontal:10,
maxHeight:deviceHeight*0.4}}
>
{this.renderTitle()}
{this.renderContent()}
</View>
</View>
</Modal>
)
}
}
The console log in the render item function gets me the number i need i just need to get this number out and back into my logistics screen
What you can do is like onTouchOutside you can pass getId function as props which will return id.
I don`t have much experience with class component. So I have add sample code in functional component. You can refer this
const MainComponent = ()=>{
const getIdFunc = (id)=>{
//You will get id here
}
return(<View>
{/* pass function here */}
<PopUpComponent getIdFunc={getIdFunc}/>
</View>)
}
const PopUpComponent = (props)=>{
return(<TouchableOpacity
onPress={()=>{
//call function by passing id here
props.getIdFunc(id)
}}
>
</TouchableOpacity>)
}
Beginner question here, not sure exactly what this would be considered, but I'm trying to make a form where a user can add and remove input rows upon pressing a button. What do I need to change to render new components or remove components when the Add or Remove buttons are pressed? Right now, the Add and Remove button change the textInput array appropriately, but components are not actually being added or removed.
Here is my current code:
FormScreen.js
import React from 'react';
import { View, StyleSheet, ScrollView } from 'react-native';
import { Button, Caption } from 'react-native-paper';
import InputCard from '../components/InputCard';
const FormScreen = props => {
const textInput = [1,2,3];
const addTextInput = () => {
let currArr = textInput;
let lastNum = currArr[currArr.length -1]
let nextNum = lastNum + 1
console.log(currArr, lastNum, nextNum);
textInput.push(
nextNum
);
console.log(textInput);
};
const removeTextInput = () => {
textInput.pop();
console.log(textInput);
};
return (
<ScrollView>
<View style={styles.col}>
<View style={styles.row}>
<Caption>Favorite colors?</Caption>
</View>
<View style={styles.row}>
<View>
{textInput.map(key => {
return (
<InputCard key={key}/>
);
})}
</View>
</View>
<View>
<View style={styles.col}>
<Button title='Add' onPress={() => addTextInput()}>Add</Button>
</View>
<View style={styles.col}>
<Button title='Remove' onPress={() => removeTextInput()}>Remove</Button>
</View>
</View>
</View>
</ScrollView>
);
};
export default FormScreen;
InputCard.js
import React, { useState } from "react";
import { View, StyleSheet } from 'react-native';
import { Caption, Card, TextInput } from "react-native-paper";
const InputCard = (props) => {
const [input, setInput] = useState('');
return (
<View>
<Card>
<Card.Content>
<Caption>Item {props.key}</Caption>
<View style={styles.row}>
<View style={styles.half}>
<TextInput
label="Input"
value={input}
onChangeText={input => setInput(input)}
mode="outlined"
style={styles.textfield}
/>
</View>
</View>
</Card.Content>
</Card>
</View>
);
}
export default InputCard;
Instead of storing it in a array, try to do something like this, using 2 states.
const [totalTextInput, setTotalTextInput] = useState([])//initial state, set it to any data you want.
const [count, setCount] = useState(0);
const addTextInput = () => {
setCount((prevState) => prevState + 1);
setTotalTextInput((prevState) => {
const newTextInput = Array.from(prevState); // CREATING A NEW ARRAY OBJECT
newTextInput.push(count);
return newTextInput;
});
};
const removeTextInput = () => {
setTotalTextInput((prevState) => {
const newTextInput = Array.from(prevState); // CREATING A NEW ARRAY OBJECT
newTextInput.pop();
return newTextInput;
});
};
And in your code:
<View>
{totalTextInput.map(key => {
return (
<InputCard key={key}/>
);
})}
</View>
Here's the function-
const setLoading = (value) => {
const messages = dashboards.data.message.filter((item) => {
const title = item.dashboardTitle || item.dashboardName;
return title.toLowerCase().startsWith(value.toLowerCase());
});
setFiltered(messages);
console.log(filtered);
};
I want to display the variable 'messages' separately in my app, how would I do that? 'messages' variable needs to be displayed within the default react native 'Text' component. I have written down 'messages' below within Text component but currently it's not displaying anything (since it is within function) -
import React, { useState, useEffect, useReducer } from 'react';
import { View, Text, StyleSheet, FlatList, ActivityIndicator, Keyboard} from 'react-native';
import { Searchbar } from 'react-native-paper';
import { theme } from '../theme';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
import { TouchableOpacity } from 'react-native-gesture-handler';
import { apiStateReducer } from '../reducers/ApiStateReducer';
import CognitensorEndpoints from '../services/network/CognitensorEndpoints';
import DefaultView from '../components/default/DefaultView';
import DashboardListCard from '../components/DashboardListCard';
const AppHeader = ({
scene,
previous,
navigation,
searchIconVisible = false,
}) => {
const [dashboards, dispatchDashboards] = useReducer(apiStateReducer, {
data: [],
isLoading: true,
isError: false,
});
const [filtered, setFiltered] = useState([]);
const setLoading = (value) => {
const messages = dashboards.data.message.filter((item) => {
const title = item.dashboardTitle || item.dashboardName;
return title.toLowerCase().startsWith(value.toLowerCase());
});
setFiltered(messages);
console.log(filtered);
};
const dropShadowStyle = styles.dropShadow;
const toggleSearchVisibility = () => {
navigation.navigate('Search');
};
useEffect(() => {
CognitensorEndpoints.getDashboardList({
dispatchReducer: dispatchDashboards,
});
}, []);
return (
<>
<View style={styles.header}>
<View style={styles.headerLeftIcon}>
<TouchableOpacity onPress={navigation.pop}>
{previous ? (
<MaterialIcons
name="chevron-left"
size={24}
style={styles.visible}
/>
) : (
<MaterialIcons
name="chevron-left"
size={24}
style={styles.invisible}
/>
)}
</TouchableOpacity>
</View>
<Text style={styles.headerText}>
{messages}
</Text>
<View style={styles.headerRightIconContainer}>
{searchIconVisible ? (
<TouchableOpacity
style={[styles.headerRightIcon, dropShadowStyle]}
onPress={toggleSearchVisibility}>
<MaterialIcons name="search" size={24} style={styles.visible} />
</TouchableOpacity>
) : (
<View style={styles.invisible} />
)}
</View>
</View>
</>
);
};
If your messages variable is an array you can map it
{messages.map((message, key)=>(
<Text style={styles.headerText}>
{message.dashboardName}
</Text>
))}
Since your messages variable is stored in 'filtered' state, you can map it by doing this:
{filtered.map((item, index) => <Text key={index}>{item.dashboardName}<Text>)}
I just started to learn React-native. In this app I have a two buttons in header, first 'Todo', second 'Tags'. I want to chang content by press on these buttons. I think I need to change state.for clarityWhat I mean, when i tap on the button Tags, below I get TagScreen component, exactly the same for the button Todo. How to connect these components so that they work correctly?
app.js
import React, { useState } from 'react'
import { StyleSheet, View, FlatList } from 'react-native'
import { Navbar } from './src/Navbar'
import { TagScreen } from './src/screens/TagScreen'
import { TodoScreen } from './src/screens/TodoScreen'
export default function App() {
const [todos, setTodos] = useState([])
const [tags, setTags] = useState([])
const [appId, setAppId] = useState([])
const addTodo = title => {
setTodos(prev => [
...prev,
{
id: Date.now().toString(),
title
}
])
}
const addTags = title => {
setTags(prev => [
...prev,
{
id: Date.now().toString(),
title
}
])
}
const removeTags = id => {
setTags(prev => prev.filter(tag => tag.id !== id))
}
const removeTodo = id => {
setTodos(prev => prev.filter(todo => todo.id !== id))
}
return (
<View>
<Navbar title='Todo App!' />
<View style={styles.container}>
<TagScreen addTags={addTags} tags={tags} removeTags={removeTags}/>
{/* <TodoScreen todos={todos} addTodo={addTodo} removeTodo={removeTodo} /> */}
{/* HERE MUST CHANGED COMPONENTS */}
</View>
</View>
)
}
const styles = StyleSheet.create({
container: {
paddingHorizontal: 30,
paddingVertical: 20
}
})
navbar.js
import React from 'react'
import { View, Text, StyleSheet, Button, TouchableOpacity } from 'react-native'
export const Navbar = ({ title }) => {
return (
<View style={styles.padding}>
<View style={styles.navbar}>
<TouchableOpacity
style={styles.button}
>
<Text>Todo</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
>
<Text>Tags</Text>
</TouchableOpacity>
<Text style={styles.text}>{title}</Text>
</View>
</View>
)
}
well you need to track the visiblity of what is visible in your state,
in your App component, do this;
const [showTodos, setShowTodos] = useState(false);
const makeTodosInvisible= () => setShowTodos(false);
const makeTodosVisible = () => setShowTodos(true);
return (
<View>
<Navbar onTodoPress={makeTodosVisible } onTagPress={makeTodosInvisible} title='Todo App!' />
<View style={styles.container}>
{showTodos
? <TodoScreen todos={todos} addTodo={addTodo} removeTodo={removeTodo} />
: <TagScreen addTags={addTags} tags={tags} removeTags={removeTags}/>
}
{/* <TodoScreen todos={todos} addTodo={addTodo} removeTodo={removeTodo} /> */}
{/* HERE MUST CHANGED COMPONENTS */}
</View>
</View>
)
and in your navbar.js do this
export const Navbar = ({ title, onTodoPress, onTagPress}) => {
return (
<View style={styles.padding}>
<View style={styles.navbar}>
<TouchableOpacity
style={styles.button}
onPreesed={onTodoPress} // will hide Tags and show Todos
>
<Text>Todo</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPreesed={onTagPress} // will show Tags and hide Todos
>
<Text>Tags</Text>
</TouchableOpacity>
<Text style={styles.text}>{title}</Text>
</View>
</View>
)
}
I am trying to create stateless component to display a Flatlist and I am struggling with the navigation.
This is my 'main' app.js, stripped down:
import React from 'react';
import { AppRegistry, FlatList, ActivityIndicator, Text, View, Image, StyleSheet } from 'react-native';
import { StackNavigator } from 'react-navigation'
import Strip from '../components/Strip'
export default class FetchData extends React.Component {
constructor(props){
super(props);
this.state ={ isLoading: true}
}
componentDidMount(){
...
}
render(){
if(this.state.isLoading){
...
}
return (
<View>
<Strip props={this.state.dataSource.strips} />
</View>
)
}
}
And this is the component:
import React from 'react';
import { FlatList, Text, View, Image, StyleSheet, TouchableOpacity } from 'react-native';
renderItem = ({item}) => (
<TouchableOpacity onPress={() => this.props.navigation.navigate('Details')} >
<View style={{width: 136}}>
...
<Text>some text</Text>
</View>
</TouchableOpacity>
);
const Strip = (props) => {
return Object.keys(props).map(function(key, i) {
return Object.keys(props[key]).map((strips, i) => {
var strip = props[key][strips];
return(
<View>
<Text>{strip.title}</Text>
<FlatList horizontal
data={strip.someobjects}
renderItem={({item}) => this.renderItem(item)}
/>
</View>
)
});
})
}
export default Strip;
The list is displayed but, of course, when I touch an item I get the 'undefined is not an object (evaluating '_this.props.navigation')' error.
I know that I can't use this.props.navigation.navigate on a stateless component but I just don't understand how I can pass the navigation props via a flatlist in a stateless component.
It has to be something really simple like using navigate('Details') and put const { navigate } = this.props.navigation; somewhere. But where?
Instead of navigate from Strip component, provide an onPress handler to Strip and navigate from there. If FetchData is part of StackNavigator then you could easily navigate from this component.
Consider following example
...
export default class FetchData extends React.Component {
...
handleOnPress = () => {
this.props.navigation.navigate('Details')
}
render() {
if(this.state.isLoading){
...
}
return (
<View>
<Strip
props={this.state.dataSource.strips}
onPress={this.handleOnPress}
/>
</View>
);
}
}
In the Strip component, you can bind the onPress handler
const Strip = (props) => {
renderItem = ({item}) => (
<TouchableOpacity onPress={props.onPress} >
<View style={{width: 136}}>
...
<Text>some text</Text>
</View>
</TouchableOpacity>
);
return Object.keys(props).map(function(key, i) {
return Object.keys(props[key]).map((strips, i) => {
var strip = props[key][strips];
return(
<View>
<Text>{strip.title}</Text>
<FlatList horizontal
data={strip.someobjects}
renderItem={({item}) => renderItem(item)}
/>
</View>
)
});
})
}
Hope this will help!
Define a function for navigation in parent and pass it to child via props.
Eg:
Parent
parentNavigate(destination){
this.props.navigation.navigate(destination);
}
render(){
if(this.state.isLoading){
...
}
return (
<View>
<Strip props={this.state.dataSource.strips} parentNavigate={(destination) => this.parentNavigate(destination)}/>
</View>
)
}
Child
renderItem = (item, parentNavigate) => (
<TouchableOpacity onPress={parentNavigate('Details')} >
<View style={{width: 136}}>
...
<Text>some text</Text>
</View>
</TouchableOpacity>
);
const Strip = (props, parentNavigate) => {
return Object.keys(props).map(function(key, i) {
return Object.keys(props[key]).map((strips, i) => {
var strip = props[key][strips];
return(
<View>
<Text>{strip.title}</Text>
<FlatList horizontal
data={strip.someobjects}
renderItem={(item, parentNavigate) => this.renderItem(item, parentNavigate)}
/>
</View>
)
});
})
}