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

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

Related

How to use navigation using functional component - react native

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 :

How to access data from navigateOptions of Navigation Drawer

I have a trouble with getting data from props in my Sidebar, I coded it like this using Navigation Drawer.
How can I access for example that text ("xd") from navigationOptions or how can i pass an object there
and read it correctly?
contentComponent: props => <SideBar {...props } />, navigationOptions: {
icon: 'xd'
},
Rest of the code
export default Sidebar = props => (
{..Something not important in that question}
<DrawerNavigatorItems {...props} style={{
}}/>
</View>
</ScrollView>
);
I'm not sure what exactly your use case is, but it might be easier to just pass icon directly to the SideBar component as a prop:
contentComponent: (props) => <SideBar {...props} icon="xd" />
Then you can retrieve the icon value passed to your SideBar component like this:
export default Sidebar = (props) => (
<ScrollView>
<Text>{props.icon}</Text>
</ScrollView>
);
I've used the Text component to give an example, but replace the Text component with the views you want.

React navigation drawer content props types definition

I am creating a custom drawer content using this guide:
const DrawerContent = (props) => (
<DrawerContentScrollView {...props}>
<AntDesign
name="close"
size={32}
onPress={() => props.navigation.closeDrawer()}
/>
<Text>TEST</Text>
<DrawerItemList {...props} />
</DrawerContentScrollView>
);
It works well, but I would like type checking on the props parameter. So I tried:
import { DrawerContentComponentProps } from '#react-navigation/drawer';
const DrawerContent = (props: DrawerContentComponentProps) => (
// Same stuff
);
But my IDE is now telling me that props.navigation.closeDrawer does not exist, but it does.
What is the correct way to define the props type of the DrawerContent function?
This is a know issue of react-navigation library: https://github.com/react-navigation/react-navigation/issues/6790
In order to make the warning disappear waiting the fix, you can use this notation:
import { DrawerActions } from '#react-navigation/native';
<AntDesign
name="close"
size={32}
// #see https://github.com/react-navigation/react-navigation/issues/6790
onPress={() => navigation.dispatch(DrawerActions.closeDrawer())}
/>

this.props in component does not contain navigation property

I want to navigate from one screen to another by this.props.navigation.navigate('Second Screen') but property 'navigation' does not contain in the props. Get error:
Property 'navigation' does not exist on type 'Readonly<{}> & Readonly<{ children?: ReactNode; }>'
import React, { Component } from "react";
import styles from "./style";
import { Keyboard, Text, View, TextInput, TouchableWithoutFeedback, KeyboardAvoidingView } from 'react-native';
import { Button } from 'react-native-elements';
export default class SignInScreen extends Component {
render() {
return (
<KeyboardAvoidingView style={styles.containerView} behavior="padding">
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.loginScreenContainer}>
<View style={styles.loginFormView}>
<Text style={styles.logoText}>Book Market</Text>
<TextInput placeholder="Email" placeholderTextColor="#c4c3cb" style={styles.loginFormTextInput} />
<TextInput placeholder="Password" placeholderTextColor="#c4c3cb" style={styles.loginFormTextInput} secureTextEntry={true} />
<Button
buttonStyle={styles.loginButton}
onPress={this.props.navigation.navigate('Home')}
title="Login"
/>
</View>
</View>
</TouchableWithoutFeedback>
</KeyboardAvoidingView>
);
}
}
You can only access it through the parent element. Pass navigation as a prop to its children to use it
Eg:
<Child navigation={this.props.navigation} />
You can do what was already suggested, pass the navigation prop down to your target component
Ex:
<TargetComponent navigation={this.props.navigation} />
Or you can use withNavigation HOC from react-natigation.
Ex:
import {withNavigation} from 'react-navigation'
...
export default withNavigation(Child)
Hope it helps.
Okay, I find a solution. At first, I need to change extends of my class like
export default class SignInScreen extends Component<{navigation: any}>
Then change onPress action:
<Button
buttonStyle={styles.loginButton}
onPress={() => this.onSignInPress()}
title="Login"
/>
private onSignInPress() {
this.props.navigation.navigate('Home');
}
I know this is an old question, but since the problem of undefined navigation property still exists at least for those who use EXPO managed approach, I'll write my solution hopefully it'll save someone's day.
After searching for hours I found no way to fix this bug and find a way to add navigation property to this.props. Finally, I solved the problem by using NavigationContext in this way:
<NavigationContainer>
<NavigationContext.Provider>
<Stack.Navigator>
...
</Stack.Navigator>
</NavigationContext.Provider>
</NavigationContainer>
Then get the navigation in a consumer:
<NavigationContext.Consumer>
{navigation => {
return (
<Button onPress={() => this.onButtonPress(navigation)} />
);
}}
</NavigationContext.Consumer>
And finally:
onButtonPress(navigation) {
try {
navigation.navigate(RouteNames.FORGOTTEN_PASSWORD_SCREEN);
} catch (e) {
this.setState({ errors: [e.message] });
}
}

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