React Native Stacknavigation Custom back button on defaultNavigationOptions - javascript

I currently have a static navigationOptions on every single page where I override the backbutton. I'm trying to change this so it uses defaultNavigationOptions instead. How do I access the back functionality of the navigationstack from the navigation file itself?
Current code:
const LoginNavigator = createStackNavigator(
{
// screens
},
{
headerLeft: (
<TouchableHighlight
onPress={() => /* navigate back */}
style={{ alignSelf: "center", marginLeft: 10 }}
>
<FontAwesomeIcon icon={faArrowLeft} color="#ffffff" />
</TouchableHighlight>
)
}
}
);
export const LoginNavigation = createAppContainer(LoginNavigator);
This gets imported into the main app, may that help.

Related

React Native: How to create elements and return them in a function

I am new to React Native
and I want to create elements and return them with a button onPress function, I donĀ“t want to hide and show like a Modal, else create them.
import React from "react"
import { Button, StyleSheet, Text, View } from 'react-native';
function createElement() {
return(
<View style={styles.elementStyle}>
<Text style={styles.txt}>ELement</Text>
</View>
)
}
const App = () => {
return (
<View style={{ flex: 1,backgroundColor: '#fff', alignItems: 'center',justifyContent: 'center',}}>
<Button title="create element" onPress={() => createElement()}/>
</View>
);
}
export default App;
const styles = StyleSheet.create({
container: {flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center',
},
elementStyle: { backgroundColor:'grey', width:'95%', height: 90, margin: 10, justifyContent: "center", borderRadius: 10, fontWeight: "bold" },
txt: {textAlign:'center',fontSize:28,color:'#fff',fontWeight: "bold"}});
I tried with functions that return components, but nothing works
Do you want to have multiple elements or just a single modal?
For multiple elements, do the below. For a single element, it's easiest to just use show / hide logic.
The best way to do this is have an array in state like so:
const [elementArray, setElementArray] = useState();
Your createElement method instead should become two parts, adding elements to the array with the content you want, which you can then render in the main return function with a map method.
const addElement = () => {
// Just using text here. If you want a more complex element, you will have to add things to the object.
const newElementText = 'Element';
const newElementArray = elementArray.slice();
newElementArray.push(newElementText);
setElementArray([...newElementArray]);
}
Then in your return function in the component:
{elementArray.map((element) => {
return (
<View style={styles.elementStyle}>
<Text style={styles.txt}>element</Text>
</View>
);
}
)}
Make sure you add a useEffect hook so the component rerenders when you add a new element:
useEffect(()=> {}, [elementArray])
You can't navigate to a component like that. If you are making it so your component appears on the click of a button I suggest building a Stack by importing react-native/navigation. Then, building your structure as shown. My explanation might not have been the best because your initial code was unstructured. This should give you an even better answer. docs
const navigation = useNavigation();
function createElement() {
return(
<View style={styles.elementStyle}>
<Text style={styles.txt}>Element</Text>
</View>
)
}
function Home() {
return (
<View style={{ flex: 1,backgroundColor: '#fff', alignItems: 'center',justifyContent: 'center',}}>
<Button title="create element" onPress={() => navigation.navigate("Element")}/>
</View>
);
}
const App = () => {
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Element" component={CreateElement} />
</Stack.Navigator>
}

React Native Components Do Not Recognize Taps

I have just recently switched to React navigation v6 in my RN app and I can't seem to understand why my Button(s) and Touchable(s) do not recognize onPress function the second time they are being pushed.
The scenario:
I launch Home Screen.
Press go to test screen button. The console prints the message.
On Test Screen press go back. The console prints the message. I go back.
Back on the Home Screen the button doesn't work anymore. Console does not print the message
Home.tsx
<View style={{ flex: 1, paddingTop: 30 }}>
<Button
title='go to test screen'
onPress={() => {
console.log('pressed to test');
navigate(TEST_SCREEN);
}}
/>
</View>
TestScreen.tsx
<View style={{flex: 1, paddingTop: 30}}>
<Button
title='go back'
onPress={() => {
console.log('pressed go back');
goBack();
}}
/>
</View>
navigate func:
export function navigate(name: string, params?: any | undefined) {
if (navigationRef.isReady()) {
navigationRef.navigate(name, params);
}
}
navigator:
const Home = createStackNavigator();
export default function HomeNavigator(): JSX.Element {
return (
<Home.Navigator
initialRouteName={HOME_SCREEN}
screenOptions={{ headerShown: false }}
>
<Home.Screen name={HOME_SCREEN} component={HomeScreen} />
<Home.Screen name={TEST_SCREEN} component={TestScreen} />
</Home.Navigator>
);
}
routes:
export const HOME_SCREEN = 'Home';
export const TEST_SCREEN = 'Test';

React Native Loader in every component or root?

Should we use the Loader component (Any custom Loader) in every Component and use dedicated state reducer variables to toggle it with a relative API call or should we have a Loader in the root of the application and toggle it on any API instance?
If we use a root Loader component, and it has properties
{position: 'absolute', top:0, bottom:0, right:0, left:0}
(Full-screen loader). Although it would get rid of many lines of code to toggle every loader component separately, but wouldn't it stop the user from any other page if one API endpoint crashes or takes too long to load.
What would the best practice be?
I wrap all of my screen with custom component, so I have a component that is wrapped all screen and I show loading on this component:
ScreenContainer component:
function ScreenContainer({
barStyle = "dark-content",
statusBarColor = Colors.whiteFFF,
children,
containerStyle,
loading = false,
translucent = false,
}: ScreenContainerProps) {
useFocusEffect(
React.useCallback(() => {
StatusBar.setBarStyle(barStyle);
StatusBar.setBackgroundColor(statusBarColor);
StatusBar.setTranslucent(translucent);
}, []),
);
return (
<View
style={[
{
flex: 1,
},
containerStyle,
]}
>
{loading ? <LoadingOverlay show={loading} /> : null}
{children}
</View>
);
}
LoadingOverlay Component:
function LoadingOverlay({ show = false }: LoadingOverlayProps) {
return (
<Modal
transparent
visible={show}
animated
animationType="fade"
presentationStyle="overFullScreen"
>
<StatusBar backgroundColor="rgba(0,0,0,0.3)" barStyle="light-content" />
<View
style={{
backgroundColor: "rgb(33, 33, 33)",
opacity: 0.4,
alignItems: "center",
justifyContent: "center",
flex: 1,
}}
>
<TLoader />
</View>
</Modal>
);
}

How to use Drawer in react native proper way?

It makes on App.js page
const MyApp = createDrawerNavigator({
Requester: {
screen: Requester,
},
Forgot: {
screen: Forgot,
},
});
I want to show a Welcome page with a menu button on it. When user clicks the menu button a drawer menu should appear.
<View style={{marginTop:30, justifyContent: 'center', backgroundColor:
'#095473', paddingLeft: '80%', flexDirection: 'row' }}>
<TouchableOpacity onPress={() =>
{this.props.navigation.navigate('DrawerOpen'); } }>
<Icon
name="menu"
size={60}
color="white"
//onPress={() => this.props.navigation.navigate("Register")}
/>
</TouchableOpacity>
</View>
But Drawer was not open why ? please guide
I'd assume you are using recent react-navigation, because you use createDrawerNavigator function. Based on the latest doc, they replaced the previous API with the newer one. See here
to open the drawer, you need to use this.props.navigation.openDrawer() instead this.props.navigation.navigate('DrawerOpen').
So the rough implementation would be like this:
<TouchableOpacity onPress={this.props.navigation.openDrawer} />
full reference how to implement it:
https://reactnavigation.org/docs/en/drawer-based-navigation.html

Using react-native-modalbox in ListView causes modalbox to only fill the list item space instead of full screen?

When I use the package react-native-modalbox with a FlatList (each list item can spawn a distinct modal when tapped), the modal that is spawned only fills the area of the list item instead of going full screen like it normally should.
A working snack that shows the issue is here:
https://snack.expo.io/BkICbjwWQ
For completeness I'll paste the code in here as well:
import React, { Component } from 'react';
import { Text, View, StyleSheet, FlatList, Button } from 'react-native';
import { Constants } from 'expo';
import Modal from "react-native-modalbox";
// You can import from local files
import AssetExample from './components/AssetExample';
// or any pure javascript modules available in npm
import { Card } from 'react-native-elements'; // Version can be specified in package.json
export default class App extends Component {
render() {
let myRefs = [];
return (
<View style={styles.container}>
<FlatList
data={[{key: 'a'}, {key: 'b'}]}
renderItem={({item}) => <View>
<Modal
style={[styles.modal]}
ref={(modalItem) => {myRefs[item.key] = modalItem;} }
swipeToClose={true}
onClosed={this.onClose}
onOpened={this.onOpen}
onClosingState={this.onClosingState}>
<Text style={styles.text}>Basic modal</Text>
</Modal><Text>{item.key}</Text><Button title="Basic Modal" onPress={() => myRefs[item.key].open()} style={styles.btn}>Basic modal</Button></View>}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
});
I basically have the same question/problem as (react-native-modalbox stuck in child component context) but there was no answer to that question and he did not provide enough details with a minimum working example.
Your modal component is inside the rendered item. This causes it to be bound to the item. Although you can fix this issue by using appropriate props or some custom styling, this is not efficient. You would have 1000 modal components if you had 1000 items in your list.
You should move out your modal component and make it sibling to the FlatList. This way you would have only single modal. You can change the contents of the modal with a state value.
Sample
export default class App extends Component {
render() {
let myRefs = [];
return (
<View style={styles.container}>
<Modal
style={[styles.modal]}
ref={modalItem => { myRefs['modal'] = modalItem; }}
swipeToClose={true}
onClosed={this.onClose}
onOpened={this.onOpen}
onClosingState={this.onClosingState}>
<Text style={styles.text}>Basic modal</Text>
</Modal>
<FlatList
data={[{ key: 'a' }, { key: 'b' }]}
renderItem={({ item }) => (
<View>
<Text>{item.key}</Text>
<Button
title="Basic Modal"
onPress={() => myRefs['modal'].open()}
style={styles.btn}>
Basic modal
</Button>
</View>
)}
/>
</View>
);
}
}

Categories

Resources