props automaticaly given as parameter - react-native

I would like to use a custom component and I need it to have the navigation props in order to navigate inside this component.
For now I'm passing navigation as a classic prop:
<MyVideo videoSource={require('../Image/S01E01DB.mp4')}
thumbnailSource={require('../Image/S01E01DB.mp4')}
navigation={this.props.navigation}/>
But is it possible to always have him set as it was given as a prop?
I need that in order to simplify the usage of my prop.

As said in the comments section by #jonrsharpe, the navigation props is only automatically given to routes declared with createStackNavigator or the others react-navigationnavigators`
There's a tool you can use from react-navigation to connect any component to your parent navigator:
import { withNavigation } from 'react-navigation';
class MyBackButton extends React.Component {
render() {
return <Button title="Back" onPress={() => { this.props.navigation.goBack() }} />;
}
}
// withNavigation returns a component that wraps MyBackButton and passes in the
// navigation prop
export default withNavigation(MyBackButton);
In case of nested navigators, the withNavigation function will get the closest parent of your component.
You will find more informations on this link

Related

In React Native app passing navigation to class component puts it in another navigation object

In my React Native app, when I pass navigation to a class component, it puts it in another navigation object and now I have to add one more navigation to call the navigate() method.
So, instead of this.props.navigation.navigate("somewhere"),
I have to use this.props.navigation.navigation.navigate("somewhere")
Here's how I pass navigation from a functional to a class component:
const ParentComponent = ({ navigation }) => {
return(
<View>
<ChildComponent navigation={navigation} />
</View>
);
}
export default ParentComponent;
And in the child component which happens to be a class component with access to Redux store, I recieve navigation like this:
class ChildComponent extends Component {
render() {
return(
<View>
<TouchableOpacity onPress={() => this.props.navigation.navigation.navigate("Route123")}>
<Text>Go to Route 123</Text>
</TouchableOpacity>
</View>
);
}
}
function mapStateToProps(state, navigation) {
myAccount: state.account.myAccount,
navigation: navigation
}
export default connect(mapStateToProps)(ChildComponent);
Notice that in the ChildComponent, I had to add one more navigation to access the navigate function i.e. this.props.navigation.navigation.navigate("Route123");
I think I'm making a fairly fundamental mistake somewhere but not sure where.
The version of React Navigation in my app is as follows and the React Native version is 0.66.3:
"#react-navigation/drawer": "^6.1.8",
"#react-navigation/material-bottom-tabs": "^6.0.9",
"#react-navigation/native": "^6.0.6",
"#react-navigation/native-stack": "^6.2.5",
As #Hagai Harari stated, you should not put navigation as the second parameter of mapStateToProps function. As described here, second parameter of mapStateProps takes ownProps which corresponds to the component props.
You can use withNavigation. But when I see your dependencies, you are using react-navigation#^6 which does not have HOC called as withNavigation.
You can choose to use this.props.navigation after removing unnecessary navigation param from mapStateToProps.
What I would suggest is to use functional component instead of class components, then you will be able to use useNavigation which react-navigation#^6 exposes. In the end, you will obtain navigation object without repetition of passing it down to children components.

How can we create a react-native component which can be displayed with .show() method

I am looking for pointers where I can start from.
I want to create a react native feedback form which can be displayed with .show method.
for eg:
export class FeedbackComponent extends React.component{
show() {
// define this method in a way so that can be called from outside as FeedbackComponent.show()
// which eventually create a new screen with below rendered View
}
render (){
return <View>Feedback Form</View>
}
}
I should be able to use this Component in any other component as
import FeedbackComponent from './FeedbackComponent'
new FeedbackComponent.show()
I would always start with considering the application state. UI in React is updated whenever the State of our components changes.
In your case I would have to think of the parent context in which your feedback form will need to be displayed. In its simplest form, this context will likely be a parent screen-component within which your FeedbackForm component is either shown or hidden.
I've made a Snack of a simple implementation you can find it here: https://snack.expo.io/#stephos_/show-feedback-form
In my case, the App component is the parent screen-component within which we need to render or not render a FeedbackForm Component.
So I would start with adding the relevant state property to the App (parent screen) component like so:
state = {
feedbackFormVisible : false
}
I would then define a method within the same parent class in order to toggle the state when we need to like so:
handleFeedbackFormVisibility = () => this.setState(prevState => ({feedbackFormVisible:!prevState.feedbackFormVisible}))
This handler takes in the previous state in our parent component and toggles the value of the feedbackFormVisible property (i.e. from false to true).
In my case, I call this handler every time we press a Button component like so:
<Button title="Give Feedback" onPress={this.handleFeedbackFormVisibility}/>
You could however trigger the same handler and update the state of the parent component in any other way (i.e. after a timer expires or after a specific scroll point is passed).
The App Component's render method will then decide if the FeedbackForm component should be displayed based on the value of the feedbackFormVisible in our App Component's state. We achieve this by wrapping our FeedbackForm component within an Elvis Conditional within the render method which will return the the appropriate UI (i.e. either with a visible feedback form or not):
{ this.state.feedbackFormVisible ? () : null}
Below the full App component code:
import * as React from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import FeedbackForm from './components/FeedbackForm';
export default class App extends React.Component {
state = {
feedbackFormVisible : false
}
handleFeedbackFormVisibility = () => this.setState(prevState => ({feedbackFormVisible:!prevState.feedbackFormVisible}))
render() {
return (
<View style={styles.container}>
<Text style={styles.paragraph}>
This is the App Parent Component
</Text>
{
this.state.feedbackFormVisible ?
(<FeedbackForm />)
: null
}
<Button title="Give Feedback" onPress={this.handleFeedbackFormVisibility}/>
</View>
);
}
}
And below the Feedback Component code (Notice that the shown/hidden logic is actually handled in the parent component not in here):
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
export default class FeedbackForm extends React.Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.paragraph}>
This is the feedback form!
</Text>
</View>
);
}
}

How to call a react native function for navigation from another class

I am new in react native. I have used Wix react-native-navigation library for navigate between pages. I want to write a separate class for navigation like bellow and call it in everywhere that I need it in my project. But I get error for "this.props.componentId". Here is my function for navigation:
ScreenNavigation.js
import React,{Component} from 'react';
import {Navigation} from "react-native-navigation";
class ScreenNavigation extends Component{
constructor(props){
super(props)
}
goToScreen = (screenName) =>{
Navigation.push(this.props.componentId , {
component : {
name : screenName
}
});
}
}
const NextPage = new ScreenNavigation();
export default NextPage;
and here is my Login page (where I want to call the function):
Login.js
import React, {Component} from 'react';
import {View, Button, Text} from 'react-native';
import NextPage from "../../my_classes/ScreenNavigation"
export default class Login extends Component {
render() {
return (
<View>
<Text>Anna</Text>
<Button title={"Enter"} onPress=
{()=>NextPage.goToScreen('myRegister')}> </Button>
</View>
);
}
}
Please help me to solve my problem.
this is my index.js file:
import {Navigation} from 'react-native-navigation';
import Login from './my_screens/login&register/Login';
Navigation.registerComponent('myLogin',()=>Login);
Navigation.events().registerAppLaunchedListener(()=>{
Navigation.setRoot({
root : {
stack : {
id:'AppStack',
children : [
{
component : {
name : 'myLogin' ,
options : {
topBar : {
title : {
text : 'Login'
}
}
}
},
}
]
}
}
}
)
});
Please follow the official documentation first. According to documentation you must register component screen first. Otherwise you cannot navigate to that screen. Secondly you are not passing any props. So its actually undefined.
If you want to execute a function of a component into another component there is two ways to todo that.
By passing prop into your child component like
<RootcComponent
<Login gotoScreen={this. goToScreen} />
/>
and then you need to call that function in you login component
this.props.goToScreen()
But if this component is not your child component then you need to pass this is in your navigation params like this
this.props.navigation.navigate('RouteName', {goTo: this.goToScreen})
and then in your component where you want to execute this function
this.props.navigation.state.params.goToScreen()

How change a variable of a parent in react-native

I want to change client = {state:0}
You can access it by using this.client.state
I also have a child which contains a button.
I'm trying to change this 'state' variable when you press the button.
For some reason everything I find everything on the internet not working for me.
I've been stuck at it for 5 hours and I think it's time to ask help myself
import React from 'react';
import { StyleSheet, Text, View, Image, TouchableOpacity } from 'react-native';
import Home from './Components/Home';
import Activity from './Components/Activity';
export default class App extends React.Component {
client = {state:0}
render() {
if(this.client.state == 0){
return(
<View style={{flex: 1}}>
<Home />
<Child />
</View>
);
} else {
return(
<View style={{flex: 1}}>
<Activity />
<Child />
</View>
);
}
There are different ways of doing this. It could be done with Redux for example, but let's take a simpler approach.
Also note that it can't be done by props, because a child component cannot update its parents' props.
Also note that the way you are using the state seems rather strange. It should be set on the class level (or component level).
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {myProperty: 0};
}
}
You could pass a callback method to the Child React Component.
<Child callback={this.onButtonClick} />
On the Client Component, create that callback method:
onButtonClick() {
this.setState({buttonClicked: true});
}
To keep it clean, define the initial value in the constructor. You'll also have to bind the function to have a correct this parameter, otherwise the this variable will be from the event instead of the class you're expecting.
constructor(props) {
super(props);
this.state = {buttonClicked: false};
this.onButtonClick = this.onButtonClick.bind(this);
}
That's it for the Client component.
Now on the Child Component, you'll need to trigger this callback method when possible.
Imagine the Child has the following button, add an event handler on the child component as well, onChildButtonClick. You'll also have to bind in the constructor.
constructor(props) {
super(props);
// bind this for access to this class' data
this.onChildButtonClick = this.onChildButtonClick.bind(this);
}
onChildButtonClick() {
// Might want to do a typeof is function check here too
if (this.props.callback) {
// Trigger the callback on the parent component, letting it know the button was triggered
this.props.callback();
}
}
render() {
return <button onClick={this.onChildButtonClick}>Click me</button>;
}
During initialisation, the Parent component sends a callback method to the child component. Whenever the button is clicked on the child component, the child component triggers the function (callback) given by the parent, essentially running a piece of code on the parent component, which then updates the state with the requested value (could be a string, or anything).
Redux
Redux is another way of doing it, which basically keeps a sort of tracked database that can be used from any component, by pageload - however, that would require an entire tutorial.

How to Create Drawer menu without Navigation?

I am looking to create a drawer, similar to a drawer navigator, but without the routes/navigation requirement.
I plan on placing some other components there that update a query. Any recommendations? Specifically the drawer would be used to display picklists, sliders, and date range components that would update the state and variables used in updating markers rendered on a map shown on the home page.
With Redux
You can use the contentComponent of the createDrawerNavigator to create your own custom drawer and bind it to redux-store.
By dispatching the actions with relevant queries you can update the variables as they are passed from the store to your Component.
Without Redux
You can either create a CustomDrawer component with similar animation and render it in your Component or use this react-native-drawer.
import Drawer from 'react-native-drawer'
class Application extends Component {
closeControlPanel = () => {
this._drawer.close()
};
openControlPanel = () => {
this._drawer.open()
};
render () {
return (
<Drawer
ref={(ref) => this._drawer = ref}
content={<DrawerContentComponent {...// Your Updater props}/>}
>
<Component />
</Drawer>
)
}
})