React Native Pass Index to Props - react-native

I have a modal that contain icons and description and status, and i want to pass the icons and descriptions from index to the modal,I already pass the status. is there anyway to do that? sorry i'm still new to react native and thanks in advance
this is my index.js
export const img =
{
itemStatus: {
"Open": { name: 'open-book', type: 'entypo', color: '#ffb732', desc:'New Attribut, New Attention'},
"Approved": { name: 'checklist', type: 'octicon', color: '#3CB371', desc:'Approved by SPV/MNG' },
"Escalated": { name: 'mail-forward', type: 'font-awesome', color: '#ffb732', desc:'Escalated to SPV/MNG' },
"Deliver Partial": { name: 'arrange-send-to-back', type: 'material-community', color: '#8B4513', desc:'Some items in a DO have not arrived/was faulty' },
};
and this is my container
class MyRequest extends React.Component {
constructor() {
super();
this.state = {
currentStatus: null,
refreshing: false,
fetchStatus: null
};
handleShowModal = (status) =>{
this.setState({
currentStatus: status,
});
}
handleDismissModal = () =>{
this.setState({currentStatus: null});
}
<View style={[styles.panelContainer, status === 'success' ? {} : { backgroundColor: color.white }]}>
<FlatList
showsVerticalScrollIndicator={false}
progressViewOffset={-10}
refreshing={this.state.refreshing}
onRefresh={this.onRefresh.bind(this)}
onMomentumScrollEnd={(event) => event.nativeEvent.contentOffset.y === 0 ? this.onRefresh() : null}
data={content}
renderItem={({ item }) => item}
keyExtractor={(item, key) => key.toString()}
/>
</View>
<IconModal visible={this.state.modalVisible} close={this.handleDismissModal} icon={} status={this.state.currentStatus} desc={} />
}
and this is my modal
const IconModal = (props) => {
return(
<Modal
isVisible={props.visible}
onBackdropPress={props.close}
>
<View style={styles.dialogBox}>
<View style={styles.icon}>
<Icon>{props.icon}</Icon>
</View>
<View style={styles.text}>
<Text style={styles.status}>{props.status}</Text>
<Text>{props.desc}</Text>
</View>
<TouchableOpacity onPress={props.close}>
<View>
<Text style={styles.buttonText}>GOT IT</Text>
</View>
</TouchableOpacity>
</View>
</Modal>
)
}

It's a bit unclear how you plan on mapping against img.itemStatus index but you can just reference the object you want as such.
import img from '....path_to_index.js'
...
// const currentItemStatus = img.itemStatus.Open
// OR
const itemStatus = 'Open' // Or 'Approved', 'Escalated', 'Deliver Partial'
const currentItemStatus = img.itemStatus[itemStatus]
...
<IconModal
visible={this.state.modalVisible}
close={this.handleDismissModal}
icon={currentItemStatus.name} // Passing name
status={this.state.currentStatus}
desc={currentItemStatus.desc} // Passing desc
/>
...
Hope this was helpful

Related

Add a button "see more" in FlatList?

I use flatList to make a list of elements. I would like to show 15 elements and then add a button "see more" to show the next 15 etc.
I was about tu use this tutorial : https://aboutreact.com/react-native-flatlist-pagination-to-load-more-data-dynamically-infinite-list/
But I don't need to use fetch, I already have set up the data (state.listData) and in fact, I'm a little lost on how to adapt it...
I thought that maybe anyone could help me a little.
Thanks a lot
this.state = {
selectedId: '',
setSelectedId:'',
listData:''
}
};
renderItem = ({ item }) => {
const backgroundColor = item.id === this.selectedId ? "transparent" : "fff";
return (
<View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
<Item
item={item}
onPress={() => this.props.navigation.navigate('UpdateTripsForm')}
style={{ backgroundColor }}
/>
<Image source={require("../../assets/images/arrow.png")} style={{width: 15, height:15, justifyContent: 'center'}}/>
</View>
);
};
initListData = async () => {
let list = await getFlights(0);
if (list) {
this.setState({
listData: list
});
}
};
render() {
return (
<SafeAreaView style={styles.container}>
<FlatList
data={this.state.listData}
renderItem={this.renderItem}
maxToRenderPerBatch={15}
keyExtractor={(item) => item.id}
extraData={this.selectedId}
/>
<TouchableOpacity
style={styles.touchable2}
onPress={() => this.props.navigation.goBack()}
>
<View style={styles.view2}>
<Text style={styles.textimg2}>
{i18n.t("tripsform.action.back")}
</Text>
</View>
<Image
source={require("../../assets/images/btn-background.png")}
style={styles.tripsimg2}
/>
</TouchableOpacity>
</SafeAreaView>
);
};
}
I just tried this thanks to #Pramod 's answer :
const Item = ({ item, onPress, style }) => (
<TouchableOpacity onPress={onPress} style={[styles.flightsListitem, style]}>
<Text style={styles.h4}>{item.id}</Text>
</TouchableOpacity>
);
export default class FlightsList extends Component {
constructor(props) {
super(props);
this.state = {
selectedId: '',
setSelectedId:'',
listData:'',
page:1,
perPage:2,
loadMoreVisible:true,
displayArray:[]
}
};
renderItem = ({ item }) => {
const backgroundColor = item.id === this.selectedId ? "transparent" : "fff";
return (
<View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
<Item
item={item}
onPress={() => this.props.navigation.navigate('UpdateTripsForm')}
style={{ backgroundColor }}
/>
<Image source={require("../../assets/images/arrow.png")} style={{width: 15, height:15, justifyContent: 'center'}}/>
</View>
);
};
initListData = async () => {
let list = await getFlights(0);
if (list) {
this.setState({
listData: list
});
}
};
componentDidMount(){
this.setNewData()
// console.log(tempArray)
}
setNewData(){
var tempArray=[]
if(this.state.listData.length == this.state.displayArray.length){
this.setState({
loadMoreVisible:false
})
}else{
for(var i=0; i<(this.state.page*this.state.perPage); i++){
tempArray.push(this.state.listData)
}
this.setState({
displayArray: tempArray,
loadMoreVisible:true
})
}
}
loadMore(){
this.setState({
page: this.state.page+1
},()=>{
this.setNewData()
})
}
async UNSAFE_componentWillMount() {
this.initListData();
}
render() {
return (
<ImageBackground
source={require("../../assets/images/background.jpg")}
style={styles.backgroundImage}
>
<Header
backgroundImage={require("../../assets/images/bg-header.png")}
backgroundImageStyle={{
resizeMode: "stretch",
}}
centerComponent={{
text: i18n.t("mytrips.title"),
style: styles.headerComponentStyle,
}}
containerStyle={[styles.headerContainerStyle, { marginBottom: 0 }]}
statusBarProps={{ barStyle: "light-content" }}
/>
<SafeAreaView style={styles.container}>
<FlatList
data={this.state.displayArray}
renderItem={this.renderItem}
keyExtractor={(item) => item.id}
extraData={this.selectedId}
/>
{this.state.loadMoreVisible == true?
<Button style={{width:'100%', height:10, backgroundColor:'green', justifyContent:'center', alignItems:'center'}}
title = 'load more'
onPress={()=>{this.loadMore()}}>
</Button>:null}
<TouchableOpacity
style={styles.touchable2}
onPress={() => this.props.navigation.goBack()}
>
<View style={styles.view2}>
<Text style={styles.textimg2}>
{i18n.t("tripsform.action.back")}
</Text>
</View>
<Image
source={require("../../assets/images/btn-background.png")}
style={styles.tripsimg2}
/>
</TouchableOpacity>
</SafeAreaView>
</ImageBackground>
);
};
}
the flatlist is not displayed : I get :
You can user pagination method with per page limit so that you can have granular control
Load the array per page when component mount
On every click increase the per page and based on per page update data of your flat list
And also put a flag which will check when the data has ended which will help to hide the load more button when data ends
Working example: https://snack.expo.io/#msbot01/suspicious-orange
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
SafeAreaView,
SectionList,
Switch,
FlatList
} from 'react-native';
import Constants from 'expo-constants';
import Icon from 'react-native-vector-icons/FontAwesome';
import AwesomeIcon from 'react-native-vector-icons/FontAwesome';
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
export default class App extends Component<Props> {
constructor(props) {
super(props);
this.state = {
page:1,
perPage:2,
loadMoreVisible:true,
DATA: [{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'First Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Second Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'Third Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'fourth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'fifth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29sd72',
title: 'sixth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29dr72',
title: 'seventh Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d7w2',
title: 'Eight Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29ad72',
title: 'Nineth Item',
},
{
id: '58694a0f-3da1-471f-bd96-14557d1e29d72',
title: 'Tenth Item',
}],
displayArray:[]
}
}
componentDidMount(){
this.setNewData()
// console.log(tempArray)
}
setNewData(){
var tempArray=[]
if(this.state.DATA.length == this.state.displayArray.length){
this.setState({
loadMoreVisible:false
})
}else{
for(var i=0; i<(this.state.page*this.state.perPage); i++){
tempArray.push(this.state.DATA[i])
}
this.setState({
displayArray: tempArray,
loadMoreVisible:true
})
}
}
loadMore(){
this.setState({
page: this.state.page+1
},()=>{
this.setNewData()
})
}
render() {
return (
<View style={{ flex: 1 }}>
<FlatList
data={this.state.displayArray}
renderItem={({item})=>
<View style={{flexDirection:'row'}}>
<Text style={{fontSize:20}}>{item.title} </Text>
</View>
}
keyExtractor={item => item.id}
/>
{this.state.loadMoreVisible == true?
<View style={{width:'100%', height:10, backgroundColor:'green', justifyContent:'center', alignItems:'center'}} onClick={()=>{this.loadMore()}}>Load more</View>:null
}
</View>
);
}
}
Set data in state (already done ==> this.state.listData)
Set counter in state (initialize with 1)
Set 15 first elements in state (you can name it "renderedData" or something like that) and then increase cuonter to 1
Add a function that increases the "renderedData" by 15 items by increasing the counter by one
Add Footer component to the list which will call the function you created in stage 3
To take only 15( or 30/45/60 etc..) items from the list you can do something like this:
this.setState({ renderedItem: listData.slice(0, counter*15) })

using classes and rendering api call in React Native

I am totally new in React Native, I am having problem rendering data from API call. When I do it inside function it is working for me when I am using useEffect... but in the Class I cannot use that.
Here is example of my code...
export default class Categories extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
data: [],
error: null,
};
}
componentDidMount() {
this.regionsGetRequest();
}
regionsGetRequest = () => {
this.setState({ loading: true });
const fetchData = async () => {
const result = await axios(
'https://...........json'
);
this.setState({
data: result.data,
error: result.error || null,
loading: false,
});
};
fetchData();
};
renderCategories = () => {
const categoryLive = this.state.data;
console.log(JSON.stringify(categoryLive));
I am getting in console: undefined, undefined... and then results as they should... like it is running 3 times for some reason... if I try to put above renderCategories:
componentDidMount() {
renderCategories();
}
I am getting just one undefined... when I connect variable categoryLive nothing is loading.
Sorry I have been strugling with this one... any help is really appreciated!!
No matter what I do, I am always getting 3 calls... first two empty object [], and third I get real results dumped in console. So my categories are not rendering.. they are empty.
Here is updated code, and I am posting whole file, it might ring some bells.
export default class Categories extends React.Component {
state = {
myData: [],
};
componentDidMount() {
axios
.get('https://..............json')
.then((res) => {
const myData = res.data;
this.setState({ myData });
});
}
renderCategories = () => {
const categoryLive = this.state.myData;
console.log(JSON.stringify(categoryLive));
const { navigation, route } = this.props;
const tabId = route.params?.tabId;
const categories = tabId
? categoryLive[tabId]
: categoryLive.victoria_bc;
//console.log(route.params?.tabId);
return (
<ScrollView
showsVerticalScrollIndicator={false}
contentContainerStyle={styles.categoryList}
>
<Block flex>
{categories.map((category) => (
<TouchableWithoutFeedback
key={`category-${category.id}`}
onPress={() => navigation.navigate('Category', { ...category })}
>
<Block flex card style={[styles.category, styles.shadow]}>
<ImageBackground
source={{ uri: category.image }}
style={[
styles.imageBlock,
{ width: width - theme.SIZES.BASE * 2, height: 252 },
]}
imageStyle={{
width: width - theme.SIZES.BASE * 2,
height: 252,
}}
>
<Block style={styles.categoryTitle}>
<Text size={18} bold color={theme.COLORS.WHITE}>
{category.title}
</Text>
</Block>
</ImageBackground>
</Block>
</TouchableWithoutFeedback>
))}
</Block>
</ScrollView>
);
};
render() {
return (
<Block flex center style={styles.categories}>
{this.renderCategories()}
</Block>
);
}
}
When I put it like this: I am getting default category ( and all data just fine... ) but my navigation is not working any more... (route.params?.tabId is not updating)
axios
.get('https://.............json')
.then((res) => {
this.setState({
myData: res.data,
error: res.error || null,
loading: false,
});
console.log('inside .then----' + JSON.stringify(this.state.myData));
const { navigation, route } = this.props;
const tabId = route.params?.tabId;
const tmpCategories = tabId
? this.state.myData[tabId]
: this.state.myData.victoria_bc;
this.setState({ categories: tmpCategories });
//console.log(route.params?.tabId);
});
If I put it like this as below... category is empty for me:
axios
.get('https://.............json')
.then((res) => {
this.setState({
myData: res.data,
error: res.error || null,
loading: false,
});
console.log('inside .then----' + JSON.stringify(this.state.myData));
});
const { navigation, route } = this.props;
const tabId = route.params?.tabId;
const tmpCategories = tabId
? this.state.myData[tabId]
: this.state.myData.victoria_bc;
this.setState({ categories: tmpCategories });
//console.log(route.params?.tabId);
Final code that is working for me..
export default class Categories extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true,
myData: [],
error: null,
};
}
componentDidMount() {
this.renderCategories();
}
renderCategories = () => {
axios
.get('https://.............json')
.then((res) => {
this.setState({
myData: res.data,
error: res.error || null,
loading: false,
});
//console.log('inside .then----' + JSON.stringify(this.state.myData));
});
};
render() {
if (this.state.loading) {
return (
<View
style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}
>
<ActivityIndicator />
</View>
);
} else {
const { navigation, route } = this.props;
const tabId = route.params?.tabId;
const categories = tabId
? this.state.myData[tabId]
: this.state.myData.victoria_bc;
//console.log(route.params?.tabId);
return (
<Block flex center style={styles.categories}>
<ScrollView
showsVerticalScrollIndicator={false}
contentContainerStyle={styles.categoryList}
>
<Block flex>
{categories.map((category) => (
<TouchableWithoutFeedback
key={`category-${category.id}`}
onPress={() =>
navigation.navigate('Category', { ...category })
}
>
<Block flex card style={[styles.category, styles.shadow]}>
<ImageBackground
source={{ uri: category.image }}
style={[
styles.imageBlock,
{ width: width - theme.SIZES.BASE * 2, height: 252 },
]}
imageStyle={{
width: width - theme.SIZES.BASE * 2,
height: 252,
}}
>
<Block style={styles.categoryTitle}>
<Text size={18} bold color={theme.COLORS.WHITE}>
{category.title}
</Text>
</Block>
</ImageBackground>
</Block>
</TouchableWithoutFeedback>
))}
</Block>
</ScrollView>
</Block>
);
}
}
}
export default class Categories extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
myData: [],
error: null,
categories: []
};
}
componentDidMount() {
renderCategories();
}
renderCategories = () => {
this.setState({ loading: true });
axios
.get('https://..............json')
.then((res) => {
this.setState({ myData: res.data,
error: res.error || null,
loading: false
});
const categoryLive = this.state.myData;
console.log(JSON.stringify(categoryLive));
});
};
render() {
// Set params in your render method :
const { navigation, route } = this.props;
const tabId = route.params?.tabId;
if (this.state.loading){
return (
<View style={{ flex : 1, alignItems: 'center', justifyContent: 'center' }}>
<ActivityIndicator/>
</View>
);
}
return (
// assign in your return statement
this.setState({ categories: tabId
? categoryLive[tabId]
: categoryLive.victoria_bc;})
//console.log(route.params?.tabId);
const { categories } = this.state.categories;
<Block flex center style={styles.categories}>
<ScrollView
showsVerticalScrollIndicator={false}
contentContainerStyle={styles.categoryList}
>
<Block flex>
{categories.map((category) => (
<TouchableWithoutFeedback
key={`category-${category.id}`}
onPress={() => navigation.navigate('Category', { ...category })}
>
<Block flex card style={[styles.category, styles.shadow]}>
<ImageBackground
source={{ uri: category.image }}
style={[
styles.imageBlock,
{ width: width - theme.SIZES.BASE * 2, height: 252 },
]}
imageStyle={{
width: width - theme.SIZES.BASE * 2,
height: 252,
}}
>
<Block style={styles.categoryTitle}>
<Text size={18} bold color={theme.COLORS.WHITE}>
{category.title}
</Text>
</Block>
</ImageBackground>
</Block>
</TouchableWithoutFeedback>
))}
</Block>
</ScrollView>
</Block>
);
}
}

How to call Parent component function inside custom drawer

I am beginner in React Native. I am getting stuck in one issue. I have one Parent component Home.js in which there is Tab navigator on click of tab 3 child components replace based on selected key. In same page, I have custom drawer.Now, I want to change tabs on click of custom drawer's option & same thing when my 1st tab selected 1st option of drawer also set selected. How can i achieve this.
Here is my navigation Drawer :
export default MyDrawerNavigator = DrawerNavigator({
Page1: {
screen: props => <Home {...props} />,
}
},
{
contentComponent: props => (<CustomSideMenu {...props} />),
drawerWidth: (getScreenWidth() * 2.5) / 3,
}
);
Here is my Home class I want to access goToNextTab() inside Custom drawer
export class Home extends React.Component {
static navigationOptions = hidenavigation;
constructor(props) {
super(props);
}
apply_header = (val) => {
this.props.navigation.setParams({ Title: val });
}
goToNextTab = (tabName) => {
this.setState({ activeTab: tabName });
}
openDrawer() {
this.props.navigation.openDrawer();
}
tabs = [{
key: 'Dashboard',
icon: 'speedometer',
label: 'Dashboard',
pressColor: 'rgba(255, 255, 255, 0.16)'
},
{
key: 'Add Diamond',
icon: 'plus-circle-outline',
label: 'Add Diamond',
pressColor: 'rgba(255, 255, 255, 0.16)'
},
{
key: 'Diamond',
icon: 'diamond-stone',
label: 'Diamond',
pressColor: 'rgba(255, 255, 255, 0.16)'
}]
state = {
activeTab: 'Dashboard',
showFooter: true
};
renderIcon = icon => ({ isActive }) => (
<Icon size={24} color={isActive ? COLOR.action_bar : COLOR.tab_deselected_text_color} name={icon} />
)
renderTab = ({ tab, isActive }) => (
<FullTab isActive={isActive} key={tab.key} label={tab.label} labelStyle={isActive ? style.activeText : style.deactiveText} renderIcon={this.renderIcon(tab.icon)} />
)
render() {
const propsForChild = {
goToNextTab: (tabName) => this.goToNextTab(tabName),
openDrawer: () => this.openDrawer()
};
const propsForNav = {
nav: this.props,
openDrawer: () => this.openDrawer()
};
const addDimPropsForChild = {
openDrawer: () => this.openDrawer()
}
return (
<View style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
{
this.state.activeTab === 'Add Diamond' ? <Add_Dimond_Stack screenProps={addDimPropsForChild} /> : this.state.activeTab === 'Diamond' ? <Dimond_List_stack screenProps={propsForNav} /> : <Dashboard_Stack screenProps={propsForChild} />
}
</View>
{
this.state.showFooter ?
<BottomNavigation activeTab={this.state.activeTab} renderTab={this.renderTab} tabs={this.tabs} onTabPress={newTab => { this.setState({ activeTab: newTab.key }); }} />
: null
}
</View>
);
}
componentWillMount() {
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow.bind(this));
this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide.bind(this));
}
componentWillUnmount() {
this.keyboardDidShowListener.remove();
this.keyboardDidHideListener.remove();
}
_keyboardDidShow() {
//alert('Keyboard Shown');
this.setState({ showFooter: false })
}
_keyboardDidHide() {
//alert('Keyboard Hidden');
this.setState({ showFooter: true })
}
componentDidMount() {
printLogs('call', 'componentDidMount')
const { setParams } = this.props.navigation;
setParams({ myProps: 'test' });
}
}
Here is my Custom Drawer in which i want to access setSelectedPos() from Home tab click
export default class Custom_Side_Menu extends React.Component {
static navigationOptions = { hidenavigation };
state = {
current_selected: 0
}
setSelectedPos(pos) {
this.setState({ current_selected: pos });
}
closeNavigationPanel(pos) {
if (pos != 3) {
this.props.navigation.closeDrawer();
}
}
redirectToProfile() {
new NavigationRedirection().goToNextScreen('profile', this.props);
}
selectedColor(pos) {
if (this.state.current_selected === pos) {
return COLOR.input_text_color;
} else {
return COLOR.input_hint_color;
}
}
render() {
return (
<ScrollView>
<View style={stylePage.bg}>
{/* */}
<View style={{ flex: 1 }}>
<View style={{ padding: 10, alignContent: 'center', flexDirection: 'row', alignItems: 'center' }}>
<TouchableOpacity onPress={() => { this.closeNavigationPanel() }}>
<Icon name="arrow-left" size={30} color={COLOR.input_text_color} />
</TouchableOpacity>
<Text style={stylePage.menu_title}>Menu</Text>
</View>
<TouchableWithoutFeedback onPress={() => {
this.redirectToProfile();
}}>
<View>
<Image style={stylePage.profileImage} source={{ uri: 'https://uinames.com/api/photos/female/22.jpg' }} />
<Text style={stylePage.name}>Ruth McCoy</Text>
<Text style={stylePage.email}>ruth.mccoy#example.com</Text>
</View>
</TouchableWithoutFeedback>
<View style={stylePage.line_seprator} />
<View style={stylePage.menu_options}>
<Text style={[stylePage.menu_text, { color: this.selectedColor(0) }]} onPress={() => this.setCurrentSelection(0)}>Dashboard</Text>
<Text style={[stylePage.menu_text, { color: this.selectedColor(1) }]} onPress={() => this.setCurrentSelection(1)}>Diamonds List</Text>
<Text style={[stylePage.menu_text, { color: this.selectedColor(2) }]} onPress={() => this.setCurrentSelection(2)}>Add diamonds</Text>
<Text style={[stylePage.menu_text, { color: this.selectedColor(3) }]} onPress={() => this.setCurrentSelection(3)}>Profile</Text>
<Text style={[stylePage.menu_text, { color: this.selectedColor(4) }]} onPress={() => this.setCurrentSelection(4)}>Change Password</Text>
</View>
</View>
<TouchableOpacity style={{ alignSelf: 'baseline' }} onPress={() => clearAllData(this.props)}>
<View style={stylePage.logout_btn}>
<IconAnt name="logout" size={25} color={COLOR.white} />
<Text style={stylePage.logout_title}>Logout</Text>
</View>
</TouchableOpacity>
<RBSheet
closeOnDragDown={true}
closeOnPressMask={false}
ref={ref => { this.RBSheet = ref }}
height={getScreenHeight() / 2} duration={250} customStyles={{
container: { padding: 10, borderTopLeftRadius: 20, borderTopRightRadius: 20 },
}}>
<ChangePassword {...this.props} RBSheet={this.RBSheet} />
</RBSheet>
</View>
</ScrollView>
);
}
setCurrentSelection(pos) {
this.closeNavigationPanel(pos);
this.setSelectedPos(pos);
if (pos === 3) {
this.redirectToProfile();
} else if (pos === 4) {
this.RBSheet.open();
} else {
printLogs('props', this.props.navigation)
}
}
}
There are two problems.
Click on drawer options to change the navigation tab
On tab change set the option as active
using redux as global store
There is an easy way out if you need redux as your global store.
first connect your components with react-redux connect
manage the activeTab state in store instead of component state
then on click of drawer option change the state in redux for your activetab
this way you are able to solve the problem 1
Also make sure you check activetab from store if matched you can update the styling for active option in drawer . So here is solution for problem 2
Using tab navigator from react-navigation
another option is using tabNavigator from react-navigation itself that way you only need to call navigator function for changing tab
and getting the active tab from navigation state
* alternate to redux *
you can use react context apis for managing your parent state if you are not using redux

React Native FlatList Touchable Opacity

I used FlatList to display the title that is in the data. I added in TouchableOpacity for the FlatList. So for example, when I click 'First', I want to show the the data from 'mood' and it will show the list of passionate,rousing and confident. I want to show the list on a new file/screen and show purely the mood of list.
This is my data:
const Mock =
[
{ title: 'First',
mood:
[
{name: 'passionate'},
{name: 'rousing'},
{name: 'confident'},
],
},
{ title: 'Second',
mood:
[
{name: 'rollicking'},
{name: 'cheerful'},
{name: 'fun'},
{name: 'sweet'},
{name: 'amiable'},
{name: 'natured'}
],
This is my FlatList code:
export default class Cluster1 extends Component{
render() {
return (
<View>
<FlatList
data={Mock}
renderItem={({ item, index }) => {
return <FlatListItem item={item} index={index} />;
}}
/>
</View>
);
}
}
class FlatListItem extends Component {
render() {
return (
<View style={styles.list}>
<View>
<TouchableOpacity>
<Text style={styles.itemTitle}>{this.props.item.title}</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
What should I do with the TouchableOpacity when I want to show the mood name when I click the title?
This is my style code
const styles = StyleSheet.create({
itemTitle:{
fontSize: 25,
fontWeight: 'bold',
color: 'white',
margin: 20,
},
},
list:{
flex: 1,
backgroundColor: '#00BCD4',
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: 'row',
},
});
You should modify your code as below to do this:
export default class Cluster1 extends Component {
render() {
return (
<View style={{ margin: 30, backgroundColor: '#ddd' }}>
<FlatList
data={Mock}
renderItem={({ item, index }) => {
return <FlatListItem item={item} index={index} />;
}}
/>
</View>
);
}
}
class FlatListItem extends Component {
state = { showItemIndex: [false, false] };
_onPress = index => () => {
let showItemIndex = this.state.showItemIndex;
showItemIndex[index] = !this.state.showItemIndex[index];
this.setState({ showItemIndex });
};
render() {
return (
<View style={styles.list}>
<View>
<TouchableOpacity onPress={this._onPress(this.props.index)}>
<Text style={styles.itemTitle}>{this.props.item.title}</Text>
</TouchableOpacity>
{this.state.showItemIndex[this.props.index] && (
<FlatList
data={this.props.item.mood}
extraData={this.state.showItemIndex}
renderItem={({ item, index }) => {
return (
<Text item={item} index={index}>
{item.name}
</Text>
);
}}
/>
)}
</View>
</View>
);
}
}
Use this, it's should be work fine for you:
Link: https://github.com/oblador/react-native-collapsible
Link: https://github.com/naoufal/react-native-accordion
Link: https://github.com/cuiyueshuai/react-native-expandable-section-flatlist
You could set a state variable which gets updated whenever your TouchableOpacity gets pressed. And then you conditionally render the title or the list of mood names:
class FlatListItem extends Component {
constructor(props) {
super(props);
this.state = {collapsed: true}
}
render() {
return (
<View style={styles.list}>
<View>
<TouchableOpacity
onPress={this.onPress}
>
<Text style={styles.itemTitle}>
{this.props.item.title}
</Text>
</TouchableOpacity>
{this.state.collapsed ?
<View /> :
<View>
{this.props.item.mood.map(mood => <Text>{mood.name}</Text>)}
</View>}
</View>
</View>
);
}
onPress = () => {
this.setState({collapsed: !this.state.collapsed})
}
}
You can do this by separating out the datasource that is required to show in the list.
First to display title: you can do something like this
export default class Cluster1 extends Component {
state = {
data: []
};
componentWillMount() {
const titles = Mock.forEach(data => data.title);
this.setState({
data: titles
});
}
onItemClick = item => {
const itemIndex = Mock.findIndex(data => (
data.title === item
));
const values = Mock[itemIndex].mood;
this.setState({
data: values
});
};
render() {
return (
<View>
<FlatList
data={this.state.data}
renderItem={({ item, index }) => {
return (
<FlatListItem
item={item}
index={index}
onItemClick={this.itemClick}
/>
);
}}
/>
</View>
);
}
}
and then in your FlatlistItem code:
class FlatListItem extends Component {
render() {
return (
<View style={styles.list}>
<View>
<TouchableOpacity onPress={() =>
this.props.onItemClick(this.props.item)
}>
<Text style={styles.itemTitle}>
{
this.props.item.name ?
this.props.item.name : this.props.item
}
</Text>
</TouchableOpacity>
</View>
</View>
);
}
}

React Native onPress active state change image source on Carousel

Trying to change image of a button on my carousel elements, currently it (below code) changes all the images when I click any of them. I'd like change that only current carousel's image. Any ideas? Thanks
class CarouselImages extends React.Component {
constructor(props) {
super(props);
this.state = {
myImagesArray: [
{
key: 1,
title: 'Category'
},
{
key: 2,
title: 'Category'
},
{
key: 3,
title: 'Category'
}
],
icon_active: false,
}
activateCarouselButton = a => {
const newState = Object.assign(
{},
{
icon_active: false,
},
{ [a]: true },
)
this.setState(newState);
}
}
render = () => {
const { icon_active } = this.state;
var myCarousel = this.state.myImagesArray.map(function (index) {
return (
<View key={index}>
<TouchableHighlight onPress={() => activateCarouselButton('icon_active')} >
<Image
source={icon_active ? require('../Image/active#2x.png') : require('../Image/disabled#2x.png')} />
</TouchableHighlight>
</View>
);
});
return (
<View>
<Carousel
style={{ backgroundColor: '#fff' }}>
{myCarousel}
</Carousel>
</View>
)
}
}
You need to hold key of the icon in the icon_active state, not a boolean. This gives you a hunch on how to do it:
render() {
const { icon_active } = this.state;
return (
this.state.myImagesArray.map((image) => {
return (
<View key={image.key}>
<TouchableHighlight onPress={() => activateCarouselButton(image.key)}>
<Image source={icon_active === image.key ? require('../Image/active#2x.png') : require('../Image/disabled#2x.png')} />
</TouchableHighlight>
</View>
)
})
)
}
<Image source={this.props.secureTextEntry ?
require('../../assets/images/signup/Showpassword.png') :
require('../../assets/images/signup/Hidepassword.png')} />