Passing React Navigation to Child of Child Component - reactjs

I'm dynamically building my "screen" with the use of child "row" and "button" components. I'm only using this method because I can't find a flex-flow property available for react-native.
So basically I'm mapping through an array of arrays to build each row, and within the row, mapping through each array to build each button. Because the onPress needs to be set in the button, I'm passing the URL for each
onPress{() => this.props.navigation.navigate({navigationURL})
as a prop, first to the row, and then to the button. The problem is I keep getting the error 'Cannot read property 'navigation' of undefined. I'm sure this is because only the actual "screens" within the navigator have access to the navigation props. I've also tried passing
navigation={this.props.navigation}
but had no success. I've looked through all of the documentation and can't seem to find anything helpful. Anyone else encountered a similar situation?

If you want to access the navigation object from a component which is not part of navigator, then wrap that component in withNavigation HOC. Within the wrapped component you can access navigation using this.props.navigation. Take a look at the official document
Sample
import { withNavigation } from 'react-navigation';
...
class CustomButton extends React.Component {
render() {
return <Button title="Back" onPress={() => {
this.props.navigation.goBack() }} />;
}
}
export default withNavigation(CustomButton);
Hope this will help!

Ahhh, silly mistake. I wasn't setting up Props in the constructor. Thank you Prasun Pal for the help! Here's my code if someone else has an issue.
import React, { Component } from 'react'
import { Image, Text, TouchableOpacity, View } from 'react-native'
import { withNavigation } from 'react-navigation'
class ButtonName extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<TouchableOpacity
onPress={() => this.props.navigation.navigate('PageName')}
>
</TouchableOpacity>
)
}
}
export default withNavigation(ButtonName);

Related

Navigation inside class component not working

While using class component I cannot use navigation its telling invalid hooks . How can I use navigation inside class component?
this is what i am trying to acheive , navigation option inside class component. actually i a m newbie .Can anyone help me?
import React, { Component } from 'react';
import { Text ,View ,TouchableOpacity } from 'react-native';
import { useNavigation } from '#react-navigation/native';
class Mpin extends Component {
const navigation= useNavigation();
render() {
return (
<Text>....</Text>
<TouchableOpacity onPress={()=>navigation.navigate('LoginPage')}>
<Text>SetMPIN</Text>
</TouchableOpacity>
);
}
}
export default Mpin;
You cannot use hooks inside class component. Inside class component you can directly access navigation object from props.
this.props.navigation.navigate('LoginPage')
Actually I can understand what you are trying to say. I came through this same kind of mistakes when I first started.
Use the below functional component inside of your class component like shown . By doing so you can access navigation inside class component.
import React, { Component } from 'react';
import { Text ,View ,TouchableOpacity } from 'react-native';
import { useNavigation } from '#react-navigation/native';
function ForgotMpin() {
const navigation = useNavigation();
return (
<View>
<TouchableOpacity
style={...}
onPress={() => navigation.navigate("ForgotPin")}
>
<Text>... </Text>
</TouchableOpacity>
</View>
);
}
class Mpin extends Component {
render() {
return (
<Text>....</Text>
<ForgotMpin screenName="forgotMpin" />
);
}
}
export default Mpin;
you can use vanilla js in those cases, the following code helps you redirect or navigate to other paths:
window.locate.replace('/pathname')
if you want to use Navigate or useNavigate you will have to convert to function component and not a class component

How to change the style of a reactjs component by code

I need to change the style of some child components of a react components. Something like this:
import React, { Component } from 'react';
class Parent extends Component {
onClickHandler = (event) => {
this.props.children[0].props.style.marginLeft = "-100%";
}
render() {
<div onClick={this.onClickHandler}>
{this.props.children}
</div>
}
}
export default Parent;
The error i'm getting is:
TypeError: Cannot add property marginLeft, object is not extensible
May you help me guys?
Thanks a lot !!
The error you are getting is because you cannot modify props, since those are immutable. A simpler approach can be done using plain CSS and simple state management.
With this technique, you need a state variable to know when to add the class modifier. That class modifier is in charge of overriding the styles of the child component.
The JS would look like this:
import React, { Component } from "react";
class Parent extends Component {
constructor() {
this.state = {
bigMargin: false
};
}
onClickHandler = (event) => {
event.preventDefault();
this.setState({ bigMargin: true });
};
render() {
return (
<div className={`parent-class ${bigMargin && 'big-margin'}`} onClick={this.onClickHandler}>
{this.props.children}
</div>
);
}
}
export default Parent;
And the CSS can be something as simple as this (or as complex as you may want)
.big-margin:first-child {
margin-left: -100%;
}
React props are immutable and you can't change them, they are read only and you can't add new properties.
This is done via Object.preventExtensions, Object.seal and Object.freeze.
To "fix" the error partialy you should define marginLeft in the first child of your Parent component
<Parent>
<p style={{marginLeft: '0'}}>1</p>
<p>2</p>
</Parent>
You will get now a new Error :
TypeError: "marginLeft" is read-only
Imagine having the ability to change props, and you pass the same prop to many children, one of them change it value, this will lead to unexpected behavior.
Try something like
Grab the element by its id on click
document.getElementById("demo").style.marginLeft = '-100px'
Or use react refs to grab the element

return from navigation in react native give me undefined in this.props.navigation.state.params.filePath

i need help :).
my project is 2 pages in react native, MainPage and SoundRecord.
my init screen is MainPage and when i press the button 'take sound'
i move to another component to record sound(i move with react native navigation).
when i come back i want to return the filePath(where it save the file..).
i want to insert it to the state.
when i do this in MainPage:
this.state{
filePath: this.props.navigation.state.params.filePath
}
it give error:
undefined is not an object(evaluating 'this.props.navigation.state.params.filePath')
and i understand this because i start my project with MainPage and i dont have the filePath from the SoundRecord page.
what can i do?
can i do check if this.props.navigation.state.params.filePath !== undefined?
how to do it? i try almost everything...
i put the relevant code:
MainPage:
import React, { Component } from 'react';
import { Platform, StyleSheet, Text, View, TouchableOpacity } from 'react-native';
import ImagePicker from 'react-native-image-picker';
import { RNS3 } from 'react-native-aws3';
import { aws } from './keys';
import SoundRecord from './SoundRecord'
export default class MainPage extends Component {
constructor(props){
super(props);
this.state={
file:'' ,
config:'',
filePath: '',
fileName: '',
tag:''
};
}
MoveToSoundRecordPage = () => {
this.props.navigation.navigate('SoundRecord');
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress={this.MoveToSoundRecordPage}>
<Text>take sound</Text>
</TouchableOpacity>
{/* <SoundRecord takeSound={this.takeSound}/> */}
<Text>{this.state.fileName}</Text>
<TouchableOpacity onPress={this.UploadToAWS.bind(this)}>
<Text>Upload To Aws</Text>
</TouchableOpacity>
</View>
);
}
}
SoundRecord when i finish to record i send the filePath like this:
finishRecord = (filePath) => {
this.props.navigation.navigate('MainPage',{filePath});
}
thank!
If you want to update something on the previous page then you can do it in the following way.
Create a function in the MainPage that updates the state with the new filepath.
Pass the function as as a param.
Use the passed function in SoundRecord to update the state in the MainPage
MainPage
In your MainPage add the following
sendFilepath = (filePath) => {
this.setState({filePath})
}
Update the MoveToSoundRecordPage function to take the sendFilepath as a parameter:
MoveToSoundRecordPage = () => {
this.props.navigation.navigate('SoundRecord', { sendFilepath: this.sendFilepath });
}
SoundRecord
Then in the SoundRecord page you want to update the finishRecord so that it calls the function that you have passed.
finishRecord = (filePath) => {
this.props.navigation.state.params.sendFilepath(filePath)
this.props.navigation.goBack();
}
Snack
Here is a snack https://snack.expo.io/#andypandy/navigation-passing-function that shows passing a function called sendFilepath from Screen1 to Screen2. Then in Screen2 it then calls the function that was passed and this updates the state in Screen1.
Please try this. It may help you
Add this in MainPage screen:
componentWillMount() {
const filePath = this.props.navigation.getParam('filePath', '');
this.setState({ filePath:filePath })
}

Proper way of defining/initializing state in reactjs or react-native

So far I understand there are two ways to define state in react class.
The first as many people use them, is as follows:
import React, { Component } from "react";
import { View, Text } from "react-native";
export default class Test extends Component {
constructor (props) {
super(props)
this.state = {
text: 'hello'
}
}
render() {
return (
<View>
<Text>{this.state.text}</Text>
</View>
);
}
}
The second one is as follows:
import React, { Component } from "react";
import { View, Text } from "react-native";
export default class Test extends Component {
state = {
text: "hello"
}
render() {
return (
<View>
<Text>{this.state.text}</Text>
</View>
);
}
}
The difference is at using constructor or not. What is the effect and is there any difference at all between the two? If there is, which one should I use?
Thank you!
Both methods are correct. Make sure you have support for class properties enabled in the babelrc. If you are using CRA both will work. Constructor one is better on the eyes if you want to seed the initial state from props.
Both methods are fine. Second one is the short-hand method

evaluating ( this.props.navigator ) Undefined is not an object

I'm getting this error even though i'm passing in the navigator porp properly.
MySetup is in this way : Main navigator Page -> FirstView (onBtnPress) -> Details
I'm getting the error when i'm calling this.navigator.push in the firstView page.
Main File:
import React, { Component, PropTypes } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Navigator
} from 'react-native';
class app extends Component{
constructor(props) {
super(props);
}
navigatorRenderScene(route, navigator) {
return <route.component navigator={navigator}/>
}
configureScene() {
return Navigator.SceneConfigs.VerticalDownSwipeJump;
}
render() {
return (
<Navigator
style={styles.container}
initialRoute= {{component: MainMapView}}
renderScene={this.navigatorRenderScene}/>
);
}
}
const styles = StyleSheet.create({
container: { flex: 1, flexDirection: 'column', padding: 20 }
});
AppRegistry.registerComponent('app', () => app);
First Component:
<ActionButton buttonColor="rgba(30,144,255,1)" style={styles.fabIcon}
onPress={this.fabPress}>
</ActionButton>
fabPress() {
this.props.navigator.push({
component : DetaislView
});
}
The error occurs on fabPress.
Any ideas on what i'm doing wrong?
try this in your FirstComponent.js:
class FirstComponent extends Component {
constructor(props) {
super(props);
this.fabPress = this.fabPress.bind(this);
}
// ... rest of the code remains the same
Why we had to do this?
Back in time when we were using React.createClass (ES5), class methods were automatically bound to the class. But when we started to extend (ES6 classes), we need to bind the methods explicitly to the class env.
fabPress being passed as an event's callback function, it is executed in another env outside the class; hence the this will be coming from the scope of execution env. But we need this of our class to access this.props.navigator :)
Just in case if anyone is interested in why this doesn't work even if you are having the function inside the class.
The function isn't binded to the class if declared as shown in the following.
theFunctionName() {
// your code
}
The function is binded to the class if it is declared with the following syntax.
theFunctionName = () => {
// your code
}
thus you can omitt the bind(this) code.
reference taken from here
Please make sure you have the necessary presets. Since the arrow function is highly experimental feature (as of this period in time)
For my case I passed in the navigator:
onPress={this.fabPress(navigator)}
fabPress(navigator) {
navigator.push({component: DetaislView});
}

Resources