How to use navigation using functional component - react native - reactjs

How can I use navigation using class component, the screens that I currently have on my app are functional components, and this is how I'm able to navigate from one page to another, but If try to implement this using functional comopenent it doesn't work.
export default function Activity({navigation}) {
return (
<View style={styles.MainContainer}>
<TouchableOpacity onPress={() => navigation.navigate("Home")}>
</TouchableOpacity>
</View>
)
}
How Can I implemented in here :/
I tried
this.props.navigation.navigate('Home')
and I got the following error/warning
cannot update a component while rendering a different component
export default class App extends React.Component {
render() {
return (
<View style={styles.MainContainer}>
<TouchableOpacity onPress={() => navigation.navigate("Home")}>
</TouchableOpacity>
</View>
)
}

For my navigation, I had to add at the beginning of the file this importation
import { useNavigation } from '#react-navigation/native'
And in my functional component
const navigation = useNavigation()
Like this :

Related

Reloading an animation React-native-animatable library

guy's I'm using the react-native-animatable library. Basically, when I load my app the animation runs, however, when I go to another tab and return to the initial page the animation doesn't run anymore. I think it's because it' doesn't get reloaded anymore and I was wondering how to reload a component. As you can see the View has an animation prop which is the animation which has to be loaded.
import React, { Component } from 'react';
import { Text, Button, StyleSheet, Image, ImageBackground, TouchableOpacity } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import LinearGradient from 'react-native-linear-gradient';
import {Fonts} from '../components/Fonts';
import { createAnimatableComponent, View, } from 'react-native-animatable';
class Home extends React.Component {
render() {
return (
<View style={styles.container}>
<View animation='bounceInLeft'
style={styles.container1}>
<View style={styles.card1}>
<ImageBackground
source={require('../images/pictures/runop.jpg')}
style={{width:'100%', height:200, }}>
<Text
style={{fontSize:30, alignSelf:'center', color:'white',
fontFamily:Fonts.Nunito}}
> Sport Schema's</Text>
</ImageBackground>
</View>
</View>
<View animation='bounceInRight' style={styles.container2}>
<View style={styles.card2}>
<Image
source={require('../images/pictures/foodop.jpg')}
style={{width:'100%', height:200}}/>
</View>
</View>
<View animation='bounceInLeft' style={styles.container3}>
<View style={styles.card3}>
<Image
source={require('../images/pictures/blogop.jpg')}
style={{width:'100%', height:200}}/>
</View>
</View>
</View>
);
}
}
Thanks for your help. I eventually got it to work with a different method.
I used the withNavigationFocus from react-navigation to get the isFocused props of the current screen. Then i just used an if statement if screen is focused then run animation else dont.
import {withNavigationFocus} from 'react-navigation';
class Profile extends React.Component {
constructor(props) {
super(props);
}
render()
// This checks if current screen is focused then run the animation otherwise dont.
{
if (this.props.isFocused && this.animation) {
this.animation.bounce(800)
}
return (
<View ref={(ref) => {this.animation = ref;}}
style={styles.container3}>
<View style={styles.card3}>
<Text> hii</Text>
</View>
</View>
);
}
}
});
export default withNavigationFocus(Profile); // <- dont forget this!!
If you are using react-navigation, below solution might work for you.
Create a function which would start the animation after some milliseconds and pass it to the next screen as params. Example,
SCREEN A
animateFunction() {
setTimeout(() => {
// start your animation
}, 100);
}
navigation.navigate(SCREEN_NAME, { startPrevScreenAnimation: animateFunction });
And in the next screen call that function when the component unmounts (componentWillUnmount()). Example,
SCREEN B
componentWillUnmount() {
this.props.navigation.state.params.startPrevScreenAnimation();
}
I said some milliseconds because you would want the animation to start once the screen transition is complete.
OR
Add a listener to your screen which fires an event when the screen is in focus.
if (this.props.navigation) {
this.willFocusSubscription = this.props.navigation.addListener(
'willFocus',
() => { // Run your animation },
);
}

Can we use state in arrow(functional) modules react native?

I'm passing settings screen to TabNavigator in my App. Can we use states in this type of export?
export default ({ navigation }) => (
<View style={styles.container}>
<Button
style={styles.itemStyle}
title="Log Out"
onPress={() => onSignOut().then(() => navigation.navigate("SignedOut"))}
/>
</View>
);
You can use state concept only in the class which extends Component{react}.
Module is stateless

Make shared component with calling navigation.navigate() inside - React Native

I want to make shared component for all screen in react native. So I can share them between main components.
See my code below, everything works but the this.props.navigation.navigation.navigate('HireJob') not working.
MyCode :
export default class MyComponent extends Component {
callAndPush = () =>{
console.log('callAndPush');
this.props.navigation.navigate('HireJob')
}
render() {
return (
<TouchableHighlight style = {{backgroundColor : 'red' , height : 30}} onPress = {() => this.callAndPush()}>
<Text>Apple</Text>
</TouchableHighlight>
);
}
}
Use of Component :
render(){
return (
<View style = {styles.scrollSty}>
<MyComponent></MyComponent>
</View>
);
}
}
it works like this, bypassing navigation prop into MyComponent.
<MyComponent {...this.props} />
Every component can be imported into other components, such as navigators. They import your scenes and navigate between them by sharing props.
To make a component and use it in different places simply create one:
export default class MyComponent extends React.Component {
render() {
return (
<Text> This is a special component </Text>
);
}
}
And in your other classes use it like this:
import MyComponent from '../path/to/MyComponent';
class AnotherComponent extends React.Component {
render() {
return (
<MyComponent />
);
}
}
Starting from React 0.14, you can create these easier using stateless components:
// A functional component using an ES2015 (ES6) arrow function:
const MyComponent = (props) => {
return <Text> This is a special component </Text>
};
You can pass data using props if you like.

How should a NavBar communicate with a Component in React Native?

I am using 'react-native-router-flux' with my React Native app and I can't seem to figure out how my Custom Nav Bar should communicate with my component?
I have the following code.
NavigationRouter.js:
<Scene key='addDrillScreen' component={AddDrillScreen} navBar={AddDrillNavBar} />
AddDrillScreen.js:
class AddDrillScreen extends React.Component {
performSave() {
// Want to call performSave() when NavBar is clicked
}
}
AddDrillNavBar.js:
class AddDrillNavBar extends React.Component {
render() {
return (
<View style={styles.saveButton}>
<TouchableOpacity onPress={() => {
// ??? How do I trigger the performSave() on my AddDrillScreen?
}}>
<Text style={styles.saveButtonText}>Save</Text>
</TouchableOpacity>
</View>
)
}
I don't understand how the two communicate
You have a couple of options here
Make performSave static
Move performSave to a different class, one that could be shared and isn't a react component
Use the best practice for this kind of action in your flux library if you use one. For instance, in redux you would have included that code in an action creator.

Differences passing Redux state through passProps with Navigator or binding state within Container

Testing React Native with Redux, and react-redux, I've found that the content of the state tree of Redux is not reflected in the display if the state is not passed through a Container.
To test this i use
react-native 0.19.0
react-redux 4.1.2
redux 3.1.7
as #alinzin explain in https://github.com/alinz/example-react-native-redux with all the tricks to setup this project. Are out there any other good solution?
The next example show a simple string as state in Redux store, and a simple action for enlarge the string.
Here is the reduce and the data as a single string in the state.
//Reducer
const reducer = (state = { data: '[][][]' }, action = {}) => {
switch (action.type) {
case ENLARGE:
return Object.assign({}, state, {
data: state.data+'[]'
})
default:
return state
}
}
The registred App is like this, nothing new. The initial route launches a Container for App1Component. This is the way for good binding state and Components (I belive)
export default class App extends Component {
render () {
return (
<Provider store={store}>
<Navigator style={{flex: 1}}
initialRoute={{
component: Container,
}}
renderScene={ (route, navigator) => {
const Component = route.component;
return (
<View style={{flex: 1, marginTop:40}}>
<Component navigator={navigator} route={route} {...route.passProps} />
</View>
);
}}
/>
</Provider>
)
}
}
The main content for both component App1Component and App2Componenet, is a simple component and just display the string, and show a 'button' to dispatch the enlarge action.
class MainContent extends Component{
render() {
return (
<View>
<Text>{this.props.data}-{this.props.data.length}</Text>
<TouchableOpacity onPress={()=>{this.props.enlarge()}} >
<Text>Click to Enlarge me!</Text>
</TouchableOpacity>
<Text> </Text>
</View>
)
}
}
There are no differences between components App1 and App2.
Just App1Component is invoked through a Container (and bind state and actions), and App2Component invoked (from App1Component) by pushing with Navigator all the same props (the same in App1Component)
Here is App1Component with a button to push next scene to App2Component and pass the same props, before binded through Container.
class App1Component extends Component {
render() {
return (
<View>
<MainContent {...this.props}/>
<TouchableOpacity onPress={()=>{
this.props.navigator.push({
name: 'App2',
component: App2Component,
passProps: {...this.props}
})
}}>
<Text>Click to Forward to App2Component {'\n'}passing props through Navigator passProps</Text>
</TouchableOpacity>
</View>
)
}
}
If you press 'enlarge' here the string is enlarged, and you can see the action reflected on the screen. Also you can see in chrome the trace for redux logger.
Here the wrapper container for App1Component
const Container = connect(
(state) => ({
data: state.data
}),
(dispatch) => ({
enlarge: () => dispatch(enlarge())
})
)(App1Component)
And Here Component 2, with back button.
If you press 'enlarge' here the string is enlarged, sure you can see the trace on chrome, but ... the action is not reflected on the screen.
class App2Component extends Component {
render() {
return (
<View>
<MainContent {...this.props}/>
<TouchableOpacity onPress={()=>{this.props.navigator.pop()}} >
<Text>Back to App1Component{'\n'}to see the change!</Text>
</TouchableOpacity>
</View>
)
}
}
After pressing Back, you can see the string modified on screen for App1Component.
As you can see I misunderstood something fundamental, but not what is.
Have i to decorate all the mains components (Pages/Scenes) with a container?
Why is wrong to pass props (previously binded by container) through passPros in Navigator? Actions are dispatched correctly, but does not reflect on the screen.
Any help is welcome.
Thanks
It looks like passProps does not propagate updates correctly. I’m not a React Native expert so I can’t confirm it, but I would definitely recommend you to use connect() for subscribing components to Redux store rather than passing props from the top.

Resources