React Native reset to in nested navigators - javascript

I'm currently building an app with a tabview that looks like this :
The code is the following :
TabView.js
resetToTab(index, opts) {
var selected = this.state.selected;
this.setState({selected: index});
this.refs.tabs.jumpTo(this.refs.tabs.state.routeStack[index]);
this.props.onTab(index);
};
renderScene = (tab, navigator) => {
return (
<Navigator
style={{backgroundColor: '#FFFFFF'}}
initialRoute={tab.component.route()}
ref="views"
renderScene={(route, nav) => {
return React.createElement(route.component, _.extend({navigator: nav}, route.passProps));
}}
configureScene={() => {
return {
...Navigator.SceneConfigs.FadeAndroid,
defaultTransitionVelocity: 1000,
gestures: {}
};
}} />
);
};
render() {
return (
<View style={styles.tabbarContainer}>
<Navigator
style={{backgroundColor: '#FFFFFF'}}
initialRouteStack={this.props.tabs}
initialRoute={this.props.tabs[this.props.initialSelected || 0]}
ref="tabs"
key="navigator"
renderScene={this.renderScene}
configureScene={() => {
return {
...Navigator.SceneConfigs.FadeAndroid,
defaultTransitionVelocity: 10000,
gestures: {}
};
}} />
{this.state.showTabBar ? [
<View key="tabBar" style={styles.tabbarTabs}>
{_.map(this.props.tabs, (tab, index) => {
return this.renderTab(index, tab.name, tab.icon, tab.pastille, tab.hasShared);
})}
</View>
] : []}
</View>
);
};
main.js
render() {
return (
<View style={{flex: 1}}>
<TabView
ref="tabs"
onTab={(tab) => {
this.setState({tab});
}}
tabs={[
{
component: Liste,
name: 'Découvrir',
icon: require('../assets/img/tabs/icons/home.png')
},
{
component: Friends,
name: 'Amis',
icon: require('../assets/img/tabs/icons/friend.png'),
pastille: this.state.friendsPastille < 10 ? this.state.friendsPastille : '9+'
},
{
component: RecoStep1,
icon: require('../assets/img/tabs/icons/add.png'),
hasShared: MeStore.getState().me.HAS_SHARED
},
{
component: Notifs,
name: 'Notifs',
icon: require('../assets/img/tabs/icons/notif.png'),
pastille: this.state.notifsPastille < 10 ? this.state.notifsPastille : '9+'
},
{
component: Profil,
name: 'Profil',
icon: require('../assets/img/tabs/icons/account.png')
}
]}
initialSkipCache={!!this.notifLaunchTab}
initialSelected={this.notifLaunchTab || 0}
tabsBlocked={false} />
</View>
);
};
Only, when tapping on the bottom menu items, I jump back to the correct route but the navigator in render scene is not reset to the first view. I've tried to access this.refs.views but it's is undefined. When resetToTab is called, I'd like to be able to do something like this.refs.views.resetTo(this.props.tabs[selected].component.route()) only this.refs.views is undefined. I'm pretty stuck on this one.

Related

react-native-tab-view jump to specific tab from react navigation screen

I have 2 libs for my navigation. React navigation v5 and react-native-tab-view. 3 tabs from react navigation : Home/Discover/Profile. Discover is a screen with react native tab view. I have few buttons in Home, after press them they should navigate me to Discover tab and specific tab in Tab View. For now, I made the navigation from Home to Discover with react navigation. But how can i jump to a specific tab after i navigate to Discover?
This is sone element in Home which holds the button that will navigate me from Home to Discover:
render() {
const { error, pending, refresh, videos } = this.props;
return (
<HomeViewItem
headerText={'Top Videos'}
footerText={'More Videos'}
navigate={() =>
this.props.navigation.navigate('TabNavigator', {
screen: 'Discover',
}) // this will navigate me to Discover
}
view={this._renderVideos(videos, pending, error, refresh)}
/>
);
}
this is tab view in Discover screen:
export default class DiscoverTabView extends React.Component<DiscoverProps> {
_StreamsRoute = () => <StreamsTabScreen navigation={this.props.navigation} />;
_NewsRoute = () => <NewsTabScreen navigation={this.props.navigation} />;
_VideosRoute = () => <VideosTabScreen navigation={this.props.navigation} />;
_RedditRoute = () => <RedditTabScreen navigation={this.props.navigation} />;
_PicturesRoute = () => (
<PicturesTabScreen navigation={this.props.navigation} />
);
state = {
index: 0,
routes: [
{ key: 'streams', title: 'Streams' },
{ key: 'news', title: 'News' },
{ key: 'videos', title: 'Videos' },
{ key: 'reddit', title: 'Reddit' },
{ key: 'pictures', title: 'Pictures' },
],
};
_handleIndexChange = (index: number) => this.setState({ index });
componentWillUpdate() {}
render() {
const renderTabBar = (
props: SceneRendererProps & { navigationState: State }
) => (
<TabBar
{...props}
indicatorStyle={{ bottom: 6 }}
style={{ backgroundColor: '#0C2B33', elevation: 0, shadowOpacity: 0 }}
scrollEnabled={true}
renderLabel={renderLabel}
renderIndicator={renderIndicator}
tabStyle={{ width: 87, height: 44 }}
/>
);
const renderLabel = ({
route,
focused,
color,
}: {
route: Route;
focused: boolean;
color: String;
}) => {
return (
<View style={{ width: 87, height: 44 }}>
<Text style={focused ? styles.active : styles.inactive}>
{route.title}
</Text>
<Image
source={
route.key === this.state.routes[this.state.routes.length - 1].key
? null
: images.tabViewSeparator
}
style={{ position: 'absolute', alignSelf: 'flex-end', top: 10 }}
/>
<Image
source={
focused ? images.tabViewIconActive : images.tabViewIconInactive
}
style={{
width: 20,
height: 20,
alignSelf: 'center',
position: 'absolute',
top: 21,
}}
/>
</View>
);
};
return (
<TabView
lazy={false}
navigationState={this.state}
renderScene={SceneMap({
streams: this._StreamsRoute,
news: this._NewsRoute,
videos: this._VideosRoute,
reddit: this._RedditRoute,
pictures: this._PicturesRoute,
})}
renderTabBar={renderTabBar}
onIndexChange={this._handleIndexChange}
initialLayout={{ width: Dimensions.get('window').width }}
/>
);
}
}
You do it by using a specific tab action: jumpTo.
The function goes as follows:
import { TabActions } from '#react-navigation/native';
const jumpToAction = TabActions.jumpTo("TabName", { params });
navigation.dispatch(jumpToAction);

React Native pass index

I am making a music app using react-native-track-player. I made 3 components called Clusters, Songlist and Play.
How screen works
Clusters component -> Songlist component -> Play component. Problem for me is that I don't know how to pass the index of the song selected to the SongList component from Clusters component which will also allow me to pass it to my Play component. I am not sure how to do it.
I created data. First screen shows title and mood(Songlist component). Second screen (Songlist shows the playlist depending on the title that I clicked.
This is my where I get my data in another file
const ClusterData = [
{
title: "Cluster1",
data: [
{ name: "passionate" },
{ name: "rousing" },
{ name: "confident" },
{ name: "boisterous" },
{ name: "rowdy" }
],
songlist: [
{
id: "2222",
url: "http://tegos.kz/new/mp3_full/Post_Malone_-_Better_Now.mp3",
title: "Better Now",
artist: "Post Malone"
},
{
id: "2",
url:
"http://tegos.kz/new/mp3_full/5_Seconds_Of_Summer_-_Youngblood.mp3",
title: "YoungBlood",
artist: "5SOS"
}
]
},
{
title: "Cluster2",
data: [
{ name: "rollicking" },
{ name: "cheerful" },
{ name: "fun" },
{ name: "sweet" },
{ name: "amiable" },
{ name: "natured" }
],
songlist: [
{
id: "1111",
url:
"http://tegos.kz/new/mp3_full/Yellow_Claw_and_San_Holo_-_Summertime.mp3",
title: "Summertime",
artist: "Yellow Claw"
},
{
id: "1",
url:
"http://tegos.kz/new/mp3_full/Luis_Fonsi_feat._Daddy_Yankee_-_Despacito.mp3",
title: "Despacito",
artist: "Luis Fonsi"
}
]
}
];
This is my Clusters screen (first screen)
export default class Clusters extends Component {
render() {
return (
<View style={styles.container}>
<SectionList
renderItem={({ item, index }) => {
return (
<SectionListItem item={item} index={index}>
{" "}
</SectionListItem>
);
}}
renderSectionHeader={({ section }) => {
return <SectionHeader section={section} />;
}}
sections={ClusterData}
keyExtractor={(item, index) => item.name}
/>
</View>
);
}
}
class SectionHeader extends Component {
render() {
return (
<View style={styles.header}>
<Text style={styles.headertext}>{this.props.section.title}</Text>
<TouchableOpacity
onPress={() => Actions.SongList({ section: this.props.section })}
>
<Text style={styles.Play}> Play</Text>
</TouchableOpacity>
</View>
);
}
}
class SectionListItem extends Component {
render() {
return (
<View>
<Text style={styles.moodname}>{this.props.item.name}</Text>
</View>
);
}
}
This is my SongList screen (second screen)
export default class App extends Component {
render() {
return (
<View>
<FlatList
data={this.props.section.songlist}
renderItem={({ item, index, rowId }) => {
return <FlatListItem item={item} index={index} />;
}}
/>
</View>
);
}
}
class FlatListItem extends Component {
render() {
return (
<View>
<TouchableOpacity
onPress={() =>
Actions.Play({
songlist: this.props.item.songlist,
item: this.props.item
})
}
>
<Text style={styles.itemTitle}>{this.props.item.songtitle}</Text>
<Text style={styles.itemArtist}>{this.props.item.artist}</Text>
</TouchableOpacity>
</View>
);
}
}
This is my Play screen
import TrackPlayer from "react-native-track-player";
export default class Play extends Component {
componentDidMount() {
TrackPlayer.setupPlayer().then(async () => {
// Adds a track to the queue
await TrackPlayer.add(this.props.item.songlist[index]);
// Starts playing it
TrackPlayer.play();
});
}
onPressPlay = () => {
TrackPlayer.play();
};
onPressPause = () => {
TrackPlayer.pause();
};
render() {
return (
<View style={styles.container}>
<View style={{ flexDirection: "column" }}>
<TouchableOpacity style={styles.play} onPress={this.onPressPlay}>
<Text
style={{
fontWeight: "bold",
textAlign: "center",
color: "white"
}}
>
Play
</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.pause} onPress={this.onPressPause}>
<Text
style={{
fontWeight: "bold",
textAlign: "center",
color: "white"
}}
>
Pause
</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
export default class App extends Component {
setSong(var selectedSong){
// do something with the selectedsong, maybe in the state
this.setState({currentSong: selectedSong});
}
render() {
return (
<View>
<FlatList
data={this.props.section.songlist}
renderItem={({ item, index, rowId }) => {
return <FlatListItem item={item} index={index} />;
}}
/>
</View>
);
}
}
You need something like this
export default class App extends Component {
this.state = {
index:0
}
setSong(var selectedSong){
var index = this.props.songlist.index(selectedSong);
this.setState({index: index});
}
render() {
return (
<View>
<FlatList
data={this.props.section.songlist}
renderItem={({ item, index, rowId }) => {
return <FlatListItem item={item} index={index} />;
}}
/>
</View>
);
}
}
class FlatListItem extends Component {
this.state = {
index:0
}
setSong(var selectedSong){
var index = this.props.songlist.index(selectedSong);
this.setState({index: index});
}
render() {
return (
<View>
<TouchableOpacity
onPress={() =>
Actions.Play({
songlist: this.props.item.songlist,
item: this.props.item,
index: this.state.index,
setSong: () => this.setSong
})
}
>
<Text style={styles.itemTitle}>{this.props.item.songtitle}</Text>
<Text style={styles.itemArtist}>{this.props.item.artist}</Text>
</TouchableOpacity>
</View>
);
}
}
just try passing a function as a prop that you can call in the child
function setSong(var selectedSong){
// do something with the selectedsong, maybe in the state
this.setState({currentSong: selectedSong});
}
and then pass this function
<TouchableOpacity
onPress={() =>
Actions.Play({
songlist: this.props.item.songlist,
item: this.props.item,
setSong: () => this.setSong
})
}
>

React Native navigation for child components in flat list

Im pretty new in React Native (and Javscript) and im trying to understand react native navigation.
I have a homeScreen, and in this screen there is a CardFlatList, which has several CardComponents. If i click on a CardComponent, a Detail Page should open and represent the information of the cardComponent.
First I tried the navigation with a button in the homeScreen and it worked. But i don't know how to pass the navigator from homescreen -> CardFlatList -> CardComponent (onPress).
My CardComponent
export default class CardComponent extends Component {
constructor(props) {
super(props)
}
render() {
return (
<View style={styles.container}>
<Card
featuredTitle={this.props.eventname}
featuredSubtitle={this.props.eventveranstalter}
image={{uri: this.props.eventimage}}
>
<View style={styles.chipContainer}>
<ChipsComponent text={this.props.eventtag1} style={{ marginBottom: 10 }} />
<ChipsComponent text={this.props.eventtag2} style={{ marginBottom: 10 }} />
<ChipsComponent text={this.props.eventtag3} style={{ marginBottom: 10 }} />
</View>
<View style={styles.cardaction}>
<Text style={styles.cardfooter}>
{this.props.eventuhr}
</Text>
<Text style={styles.cardfooter}>
{this.props.eventort}
</Text>
<Button
backgroundColor='#5ac8fa'
fontFamily='Arial'
fontWeight='bold'
buttonStyle={styles.buttonfooter}
title='Teilnehmen' />
</View>
</Card>
</View>
)
}
My homeScreen
export default class homeScreen extends Component {
static navigationOptions = {
drawerLabel: 'Home',
headerMode: 'none',
};
constructor(props) {
super(props)
}
render() {
var {navigate} = this.props.navigation;
return (
<View style={styles.containerAll}>
<Navigationbar onPressBar={()=>this.props.navigation.navigate('DrawerOpen')} />
<View style={styles.container}>
<CardFlatList navigation={this.props.navigation} />
</View>
</View>
);
}
}
my router.js
export const DrawNavigation = DrawerNavigator({
Home: {
screen: homeScreen
},
Notifications: {
screen: test,
},
});
export const Root = StackNavigator({
DrawNavigation: {
screen: DrawNavigation,
navigationOptions: {
header: false,
},
},
First: { screen: homeScreen },
Second: { screen: eventDetailScreen },
});
​
import React, { Component } from "react";
import { View, Text, FlatList, ActivityIndicator,Image } from "react-native";
import { List, ListItem, SearchBar } from "react-native-elements";
import CardComponent from './CardComponent';
function getCardComponentArray() {
var texts = ['1', '2', '3', '4', '5'];
var cardComponents = texts.map((text) => <CardComponent title={text} />);
return cardComponents;
}
function getData() {
var texts = ['1', '2', '3', '4', '5'];
return texts
}
class CardFlatList extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
data: [],
page: 1,
seed: 1,
error: null,
refreshing: false
};
}
componentDidMount() {
this.makeRemoteRequest();
}
makeRemoteRequest = () => {
this.setState({
data: getData(),
error: null,
loading: false,
refreshing: false
});
};
handleRefresh = () => {
this.setState(
{
page: 1,
seed: this.state.seed + 1,
refreshing: true
},
() => {
this.makeRemoteRequest();
}
);
};
handleLoadMore = () => {
this.setState(
{
page: this.state.page + 1
},
() => {
this.makeRemoteRequest();
}
);
};
renderSeparator = () => {
return (
<View
style={{
height: 2,
}}
/>
);
};
renderHeader = () => {
return <SearchBar placeholder="Type Here..." lightTheme round />;
};
renderFooter = () => {
if (!this.state.loading) return null;
return (
<View
style={{
paddingVertical: 20,
borderTopWidth: 1,
}}
>
<ActivityIndicator animating size="large" />
</View>
);
};
render() {
return (
// <List>
<FlatList
data={this.state.data}
renderItem={({ item }) => (
<CardComponent
eventname={'Halloween'}
eventveranstalter={'park'}
eventuhr={'17:00'}
eventort={'berlin'}
eventimage={'http://whatstonightapp.com/wp-content/uploads/2016/12/background_light-1.jpg'}
eventtag1={'party'}
eventtag2={'music'}
eventtag3={'dance'}
>
</CardComponent>
)}
keyExtractor={item => item.email}
ItemSeparatorComponent={this.renderSeparator}
// ListHeaderComponent={this.renderHeader}
ListFooterComponent={this.renderFooter}
onRefresh={this.handleRefresh}
refreshing={this.state.refreshing}
onEndReached={this.handleLoadMore}
onEndReachedThreshold={50}
/>
// </List>
);
}
}
export default CardFlatList;
You can do it as following.
render() {
return (
// <List>
<FlatList
data={this.state.data}
renderItem={({ item }) => (
<CardComponent
navigation={this.props.navigation}
eventname={'Halloween'}
eventveranstalter={'park'}
eventuhr={'17:00'}
eventort={'berlin'}
eventimage={'http://whatstonightapp.com/wp-content/uploads/2016/12/background_light-1.jpg'}
eventtag1={'party'}
eventtag2={'music'}
eventtag3={'dance'}
>
</CardComponent>
)}

React Native search function not rendering

I have two functions that are not rendering: renderTeachers() and renderSubjects(). They render based on the length of the teachers array in the state object. I console logged state.teachers and the result is as expected, the array length is more than one, but the functions still don't render. I don't understand why these functions are not rendering.
class Search extends Component {
state = {
teachers: [],
subjects: [],
rating: 3.5,
};
requestData = (queryObj) => {
console.log(queryObj);
const client = algoliasearch('__ID__', '__KEY__');
const queries = [{
indexName: 'teachers',
query: queryObj,
filters: 'Rating >= 3.5',
}, {
indexName: 'subjects',
query: queryObj,
}];
if (queryObj === '') {
this.setState({ showSearchVal: false });
} else {
client.search(queries, this.searchCallback.bind(this));
}
}
searchCallback = (err, content) => {
if (err) {
console.error(err);
return;
}
this.setState({ teachers: content.results[0].hits, subjects: content.results[1].hits });
}
renderSubjects = () => {
if (this.state.subjects.length >= 1) {
return this.state.subjects.map(subject => <SubjectDetail key={subject.objectID} subject={subject} />);
}
return null;
}
renderTeachers = () => {
console.log('in');
if (this.state.teachers.length >= 1) {
return this.state.teachers.map(teacher => <SearchDetail key={teacher.UID} person={teacher} />);
}
return null;
}
render() {
return (
<View>
<Header search onPress={() => this.searchBar.show()} />
<SearchBar
backgroundColor='#02254e'
iconColor='#4f5d6d'
placeholderTextColor='#4f5d6d'
backButton={<Icon name='keyboard-backspace' size={24} color='#4f5d6d' style={{ alignSelf: 'center' }} />}
textColor='white'
animate={false}
handleChangeText={this.requestData}
selectionColor='#01152d'
fontFamily='avenir_heavy'
backCloseSize={24}
ref={(ref) => { this.searchBar = ref; }}
/>
<View style={{ width, height, alignItems: 'center', flex: 1 }}>
<ScrollView style={{ flex: 1 }}>
<Text style={styles.topResultTextStyle}>
{this.state.subjects.length >= 1 ? 'Subjects' : ''}
</Text>
{this.renderSubjects()}
<Text style={styles.topResultTextStyle}>
{this.state.teachers.length >= 1 ? 'Teachers' : ''}
</Text>
{this.renderTeachers()}
</ScrollView>
</View>
</View>
);
}
}
export { Search };
from the code you post, I can't see a reason why teachers / subjects won't render. My question is, how do you set the teachers /subjects arrays ? without changing state / props, react component shouldn't render. Can you please share the arrays set code ?

React Native Android change scene navigator

I'm trying to build a tabview and I can't find out how to change and render scenes. My main view is this one (App.js) :
<View style={{flex: 1}}>
<TabView
ref="tabs"
onTab={(tab) => {
this.setState({tab});
}}
tabs={[
{
component: List,
name: 'Découvrir',
icon: require('../assets/img/tabs/icons/home.png')
},
{
component: Friends,
name: 'Amis',
icon: require('../assets/img/tabs/icons/friend.png'),
pastille: this.state.friendsPastille < 10 ? this.state.friendsPastille : '9+'
},
{
component: RecoStep1,
icon: require('../assets/img/tabs/icons/add.png'),
hasShared: MeStore.getState().me.HAS_SHARED
},
{
component: Notifs,
name: 'Notifs',
icon: require('../assets/img/tabs/icons/notif.png'),
pastille: this.state.notifsPastille < 10 ? this.state.notifsPastille : '9+'
},
{
component: Profil,
name: 'Profil',
icon: require('../assets/img/tabs/icons/account.png')
}
]}
initialSkipCache={!!this.notifLaunchTab}
initialSelected={this.notifLaunchTab || 0}
tabsBlocked={false} />
</View>
The TabView component is this one and it works fine. Only the navigator renders a blank screen only...
renderTab(index, name, icon, pastille, hasShared) {
var opacityStyle = {opacity: index === this.state.selected ? 1 : 0.3};
return (
<TouchableWithoutFeedback key={index} style={styles.tabbarTab} onPress={() => {
if (this.props.tabsBlocked) {
return;
}
this.resetToTab(index);
}}>
<View style={styles.tabbarTab}>
<Image source={icon} style={opacityStyle} />
{name ?
<Text style={[styles.tabbarTabText, opacityStyle]}>{name}</Text>
: null}
</View>
</TouchableWithoutFeedback>
);
}
resetToTab(index, opts) {
this.setState({selected: index});
}
renderScene = (route, navigator) => {
var temp = navigator.getCurrentRoutes();
return temp[this.state.selected].component;
}
render() {
return (
<View style={styles.tabbarContainer}>
<Navigator
style={{backgroundColor: '#FFFFFF', paddingTop: 20}}
initialRouteStack={this.props.tabs}
initialRoute={this.props.tabs[this.props.initialSelected || 0]}
ref="tabs"
key="navigator"
renderScene={this.renderScene}
configureScene={() => {
return {
...Navigator.SceneConfigs.FadeAndroid,
defaultTransitionVelocity: 10000,
gestures: {}
};
}} />
{this.state.showTabBar ? [
<View key="tabBar" style={styles.tabbarTabs}>
{_.map(this.props.tabs, (tab, index) => {
return this.renderTab(index, tab.name, tab.icon, tab.pastille, tab.hasShared);
})}
</View>
] : []}
</View>
);
}
I know I'm doing something wrong, but I can't figure out what ... Changing tabs doesn't display anything as shown below..
I used NavigatorIOS for ans iOS version that worked fine with the following navigator in the render method in TabView (I don't know how to go from the NavigatorIOS to Navigator) :
<Navigator
style={{backgroundColor: '#FFFFFF', paddingTop: 20}}
initialRouteStack={this.props.tabs}
initialRoute={this.props.tabs[this.props.initialSelected || 0]}
ref="tabs"
key="navigator"
renderScene={(tab, navigator) => {
var index = navigator.getCurrentRoutes().indexOf(tab);
return (
<NavigatorIOS
style={styles.tabbarContent}
key={index}
itemWrapperStyle={styles.tabbarContentWrapper}
initialRoute={tab.component.route()}
initialSkipCache={this.props.initialSkipCache} />
);
}}
configureScene={() => {
return {
...Navigator.SceneConfigs.FadeAndroid,
defaultTransitionVelocity: 10000,
gestures: {}
};
}} />
Try adding a
flex:1
property to the navigator. If that doesn't work, check to see that the tabbarContainer also has a
flex:1
property.
OK, I found the answer : I changed my renderScene method to the following :
renderScene = (route, navigator) => {
var temp = navigator.getCurrentRoutes();
return React.createElement(temp[this.state.selected].component, _.extend({navigator: navigator}, route.passProps));
}
Works fine now.

Categories

Resources