Navigate to a screen of parent navigator from child navigator screen - react-native

I am new to React Native and I have been building a simple Food Recipe app. My main Stack Navigator contains two screens: Bottom Tab Navigator and Recipe screen. I am in Home screen in the Tab Navigator and when I press any recipe, I want to pass recipe props and navigate to Recipe screen in the main Stack Navigator. Unfortunately, I haven't found any solution to this.
Could you please help me solve this?
This is the main file App.js
const Navigator = createBottomTabNavigator(
{
Home: Home,
Add: Add,
Profile: Profile
}
);
const Stack = createStackNavigator(
{
Navigator: Navigator,
Recipe: Recipe
},
{
headerMode: "none",
navigationOptions: {
headerVisible: false,
}
}
);
export default createAppContainer(Stack)
This is my Home Screen class
export default class Home extends Component {
render() {
return (
<SafeAreaView style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerTitle}>Recipes</Text>
</View>
<ScrollView style={styles.categoryContainer}>
<Category name={"All Foods"} recipes={recipes} />
<Category name={"Meat"} recipes={[ recipes[1], recipes[3] ]} />
<Category name={"Vegetarian"} recipes={[ recipes[0], recipes[2] ]} />
<Category name={"Desserts"} recipes={[ recipes[4] ]} />
</ScrollView>
</SafeAreaView>
)
}
}
This is the Category class
export default class Category extends Component {
render() {
return (
<View style={styles.container}>
<View style={styles.categoryHeader}>
<Text style={styles.categoryHeaderTitle}>{this.props.name}</Text>
</View>
<ScrollView >
<View style={styles.categoryContent}>
<FlatList
data={this.props.recipes}
renderItem={({ item }) => <Block name={item.name} image={item.image} time={item.time} portions={item.portions} />}
keyExtractor={(item, index) => index.toString()}
horizontal={true}
/>
</View>
</ScrollView>
</View>
)
}
}
This is the actual recipe block where I want to navigate all the way back to the Recipe screen and pass recipe props using onPress={} function
export default class Block extends Component {
render() {
return (
<TouchableOpacity style={styles.container} onPress={null} >
<Image style={styles.image} source={this.props.image} />
<Text style={styles.title}>{this.props.name}</Text>
<Text style={styles.info}>{this.props.time} min | portions: {this.props.portions}</Text>
</TouchableOpacity>
)
}
}
Thank you for all your answers

If you need the StackNavigator to display a header on top of a BottomTabNavigator i would suggest to use a StackNavigator for every child of the bottomTabBar. Doing like that you can have more screens in a single tabBarItem, and you won't have the bottomTabBar disappearing for the other screens.
If you don't mind of this, you can access your stackNavigator from his child using dangerouslyGetParent and then navigate with the props you need.
navigateToRecipe = (recipe) => {
this.props.navigation.dangerouslyGetParent().navigate("Recipe", { recipe : myRecipe}) //pass an object with the data you need
}
Then you can access your recipe props either using getParam this.props.navigation.getParam("recipe") or directly using this.props.navigation.state.params

Related

One form, but different state

I'm moving now from other technologies to React Native and I have a problem. I have one presentational component which is <TaskInput />.
const TaskInput = (props: ITaskInputProps) => {
return (
<View style={styles.container} >
<Text style={styles.title}>{props.title}</Text>
<TextInput
style={styles.input}
multiline
scrollEnabled={false}
/>
</View>
)
}
ParentComponent over TaskInput
import React from 'react';
import { View } from 'react-native';
import styles from './styles';
import TaskInputContainer from '../task-input';
interface ITaskConfigurationProps {
title: string,
isInputForm?: boolean,
isRequired?: boolean,
}
const TaskConfiguration = (props: ITaskConfigurationProps) => {
return (
<View style={(props.isRequired) ? [styles.container, {backgroundColor: '#f25e5e'}] : styles.container}>
{ props.isInputForm && <TaskInputContainer title={props.title} /> }
</View>
);
}
export default TaskConfiguration;
const TaskScreen = (props: ITaskScreenProps) => {
return (
<View style={styles.container}>
<SectionTitle title={'Task Settings'} />
<ScrollView contentContainerStyle={styles.configurations}>
<TaskConfiguration title={"What you need to do?"} isInputForm={true} isRequired={true} />
<TaskConfiguration title={"Description"} isInputForm={true} />
<TaskConfiguration title={"Deadline"} />
<TaskConfiguration title={"Priority"} />
</ScrollView>
<Button isDone={true} navigation={props.navigation} />
</View>
)
}
TaskInput component takes one prop which is title and it will be in two places on my screen. One component will be called "Enter main task", another one is "Description". But this component will accept different states like currentMainTextInput and currentDescriptionTextInput. This is my idea of re-usable component TextInput, but I can't do what I want because if I set type in one input - other input will re-render with first input (both of them are one presentational component).
I want to use this dumb component in any place of my app. I don't want to create a new identical component and duplicate code, How can I do that? (P.S. I was thinking about "redux or class/hooks", but what should I use...)

What is proper way to use Floating Button as globally in react-native?

Root component is App.js
using Redux-saga as well.
my intention is that after login i want to use float button global.
but there are 3 tabs with Tab-Navigator (e.g Mail/Profile/Gallery..) and they have each Stack Navigator.
and i want to use floating button with different functions by tabs.
For example,
Mail.js --> fab function(Write)
Profile.js --> fab function(Call, Message)
Gallery.js -- > fab function(Share, Upload)..
like that.
where should i put Fab Component to use globally??
i'm using library
https://github.com/santomegonzalo/react-native-floating-action
if there is other nice library i would accept if you guys recommend me. thanks
App.js
export default class App extends React.Component {
render() {
return (
<Provider store={store}>
<View style={styles.container}>
<ReduxNavigation />
</View>
</Provider>
)}}
You can use react-native-action-button module for action button.
if your action button is independent of current screen on which you are, then you can use it in root component, as the action button have absolute position.
here is sample code that you can use for reference.
export default class App extends React.Component {
render() {
return (
<Provider store={store}>
<View style={styles.container}>
<ReduxNavigation />
<ActionButton buttonColor="rgba(231,76,60,1)">
<ActionButton.Item buttonColor='#9b59b6' title="New Task" onPress={() => console.log("notes tapped!")}>
<Icon name="md-create" style={styles.actionButtonIcon} />
</ActionButton.Item>
<ActionButton.Item buttonColor='#3498db' title="Notifications" onPress={() => {}}>
<Icon name="md-notifications-off" style={styles.actionButtonIcon} />
</ActionButton.Item>
<ActionButton.Item buttonColor='#1abc9c' title="All Tasks" onPress={() => {}}>
<Icon name="md-done-all" style={styles.actionButtonIcon} />
</ActionButton.Item>
</ActionButton>
</View>
</Provider>
)
}
}

How can i change the FlatList item background color when button is pressed in React Native

Let's suppose that i've a FlatList with some items, i press into one of them, then opens me another screen with the details of that item. Alright, so what i need is, after pressing the button called "Got it!" and goes into the back screen(FlatList screen), how can i set the background color to green in the row selected?
So i click in one item of the FlatList, then it shows me another screen with the details of that item
Once im in the Details screen, i press the button "Got it!", and it brings me back to the FlatList screen
This is exactly what i need, set a background color only in the View shown in that item, if i press another item and do the same thing, it will be shown changed the background both of them, and so on...
NOTE: class Details and ProfileActivity are inside App.js as a childs.
class ProfileActivity extends Component
{
GetFlatListItem (Description, Tutorial, Imagen, Title) {
Alert.alert(Description);
this.props.navigation.navigate('Fourth', {Tutorial, Imagen, Title});
}
return(
<View style = { styles.MainContainer }>
<Button title="Logout" onPress={ () => goBack(null) } />
<Text style = {styles.TextComponentStyle}> { this.props.navigation.state.params.Email } </Text>
<FlatList
data={ this.state.dataSource }
ItemSeparatorComponent = {this.FlatListItemSeparator}
renderItem={({item}) => <View style={{flex: 1, flexDirection: 'row'}}> <Text style={styles.points}>+ {item.points}</Text>
<Text style={styles.flatview} onPress={this.GetFlatListItem.bind
(this, item.description, item.tutorial, item.image, item.title)} >{item.title}</Text></View>}
keyExtractor={(item, index) => index.toString()}
/>
</View>
);
class Details extends Component{
onPress = () => {
this.setState({
const {goBack} =this.props.navigation;
})
}
return(
<View style = { styles.MainContainer }>
<TouchableHighlight
style={styles.buttonStyle}
onPress={this.onPress}
>
<Text> Got it! </Text>
</TouchableHighlight>
<Text style = {styles.TextComponentStyle}> { this.props.navigation.state.params.Title } </Text>
<Image
style={{width: 66, height: 58}}
source={{uri: this.props.navigation.state.params.Imagen}}
/>
<Text style = {styles.TextComponentStyle}> { this.props.navigation.state.params.Tutorial } </Text>
</View>
);
}
export default MainProject = createStackNavigator(
{
First: { screen: App },
Second: { screen: ProfileActivity },
Fourth: { screen: Details }
});
What i think is pass some values to the method onPress() in Details class, but i don't know which one exactly and how. Can somebody help me?
You will have to create this.state.someArrayName and copy from this.props.navigation.state.params and add backgroundColor key to each object and add your color. Apply that color to your items' view background color. *{{backgroundColor : item.backgroundColor}}
Create a function changeColor to change the color of backgroundColor
In your GetFlatListItem function, pass that function to detail view
On Detail View, call that changeColor function. this.props. changeColor() when you tap Got it button.

How to handle a touch gesture by multiple components in react native?

Using React Native 0.47 and yarn, I'm creating an introduction section in which you can swipe through multiple pages and finally get to the home page.
So we swipe pages from right to left and move like this: Slide1 -> Slide2 -> Slide3 -> Slide4 -> Home . I have a component that displays a slide page which covers all of the screen. For example, first slide looks like this:
And the code for that is :
class IntroSlide extends Component {
render () {
return (
<View style={[styles.introSlide, this.props.myStyle]}>
<View style={styles.introSlideIconView}>
<Icon name={this.props.iconName} size={SLIDE_ICON_SIZE} color="white"/>
</View>
<View style={styles.introSlideTextView}>
<Text style={styles.introSlideTextHeader}> {this.props.headerText} </Text>
<Text style={styles.introSlideText}> {this.props.text} </Text>
</View>
</View>
);
}
}
And i use it that here:
import AppIntro from 'react-native-app-intro';
// Other imports here
export default class Intro extends Component {
render() {
return (
<View style={{flex: 1}}>
<AppIntro
showSkipButton={false}
nextBtnLabel={<Text style={styles.introButton}>بعدی</Text>}
doneBtnLabel={<Text style={styles.introButton}>شروع</Text>}
>
<IntroSlide
iconName="user"
myStyle={styles.introSlide1}
headerText="DontCare"
text= "SomeTextDoesntMatter"
/>
</AppIntro>
</View>
);
}
}
I'm using react-native-app-intro for this which provides me a very cool swiper but here's the problem:
I have a small View component with an Icon (react-native-vector-icons) in it as you can see that i want to rotate as i swipe to the next page. I created a panResponder in IntroSlide and set it to top View of it. but my slide can't receive any events. i think some parent views provided by react-native-app-intro captures all the events and i can still swipe through pages but no console log appears. here's what i did:
class IntroSlide extends Component {
constructor(props) {
super(props);
const panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove: () => console.log("Moving"),
});
this.pan = panResponder;
}
render () {
return (
<View
style={[styles.introSlide, this.props.myStyle]}
{...this.pan.panHandlers}
>
<View style={styles.introSlideIconView}>
<Icon name={this.props.iconName} size={SLIDE_ICON_SIZE} color="white"/>
</View>
<View style={styles.introSlideTextView}>
<Text style={styles.introSlideTextHeader}> {this.props.headerText} </Text>
<Text style={styles.introSlideText}> {this.props.text} </Text>
</View>
</View>
);
}
}
I did the same to the View component with flex: 1 and i had different result. i get console logs as expected but i can't swipe anymore. So how can i swipe through pages while receiving touch events in parent component ? (In other words, i want two different components to receive touch events, and I'm developing for android)

React-native-navigation navigate through a different component instead of from a page

My home page contains a View. This view contains a flat list with items. The flat list is being rendered through a different component
I should be able to use something like this.props.navigation.navigate('DetailPage') from the component not from my homePage.
I think i should pass the navigation as a prop to the but not sure how i could do that.
Navigation File
export const HomePageStack = StackNavigator({
Homepage:{
screen:homePage,
},
DetailPage:{
screen: DetailPage,
}
})
Home Page Screen
render(){
return(
<View>
<DetailedArea />
</View>
)}
Detailed Area
render(){
return(
<TouchableHighlight onPress={this.props.navigation.navigate('DetailPage')}>
<Text>CLICK HERE TO GO TO DETAIL PAGE</TEXT>
</TouchableHighlight>
)}
the HomeScreen has this.props.navigation, but it isn't passed down to DetailedArea.
I recommend the following:
HomeScreen
render(){
return(
<View>
<DetailedArea onNavigate={() => this.props.navigation.navigate('DetalPage')} />
</View>
)}
DetailedArea
render(){
return(
<TouchableHighlight onPress={this.props.onNavigate}>
<Text>CLICK HERE TO GO TO DETAIL PAGE</TEXT>
</TouchableHighlight>
)}