React Native Stack Navigator Use State - reactjs

I try to make Share State Data From MyStack Component.
Components of Second Data is Always changed But First Screen is not
Could you tell me about what is problem of this??
And What do i have to Change.
thank you :D
import React ,{ useState } from 'react';
import { Button, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
function First({route , navigation}) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
title={route.params.count.toString()}
onPress={() => navigation.navigate('Second')}/>
</View>
);
}
function Second({route , navigation }) {
route.params.setCount(route.params.count + 1);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
title={route.params.count.toString()}
onPress={() => { navigation.goBack()}}
/>
</View>
);
}
const Stack = createStackNavigator();
function MyStack() {
const [count, setCount] = useState(0);
return (
<Stack.Navigator>
<Stack.Screen name="First" component={First} initialParams={{ count: count , setCount : setCount }}/>
<Stack.Screen name="Second" component={Second} initialParams={{ count: count ,setCount : setCount}}/>
</Stack.Navigator>
);
}
export default function App(props) {
return (
<NavigationContainer>
<MyStack props={props}/>
</NavigationContainer>
);
}

The reason for the above not working is the FirstScreen is not being re rendered. You cant dynamically change the intialparams after the screen is rendered.
Even your screen 2 is not working properly, you set it but you see the updated value when you revisit the screen.
The way to fix this is to use the context api which you can use to skip the navigation params.
And always use a hook like useEffect or a buttonclick to update the context otherwise it would keep rerendering which would result in an error.
The code would be like below.
import React, { useState, createContext, useContext } from 'react';
import { Button, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
const appContext = createContext();
function First({ route, navigation }) {
const context = useContext(appContext);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
title={context.count.toString()}
onPress={() => navigation.navigate('Second')}
/>
</View>
);
}
function Second({ route, navigation }) {
const context = useContext(appContext);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
title={context.count.toString()}
onPress={() => {
navigation.goBack();
}}
/>
<Button
title="Add to Count"
onPress={() => {
context.setCount(context.count + 1);
}}
/>
</View>
);
}
const Stack = createStackNavigator();
function MyStack() {
const [count, setCount] = useState(0);
const state = { count, setCount };
return (
<appContext.Provider value={state}>
<Stack.Navigator>
<Stack.Screen name="First" component={First} />
<Stack.Screen name="Second" component={Second} />
</Stack.Navigator>
</appContext.Provider>
);
}
export default function App(props) {
return (
<NavigationContainer>
<MyStack props={props} />
</NavigationContainer>
);
}

Related

cannot read property 'params' of undefined react native

I'm coding product detail but can't use the params property
Cannot read property 'params' of undefined
you can see my code here
import React from 'react';
import {Image, Text, View} from 'react-native';
const ProductDetail = ({route, navigation}) => {
const productID = route.params;
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>Product Detail</Text>
</View>
);
};
export default ProductDetail;
Product Item
const CardHeight = 220;
const ProductItem = ({list}) => {
const navigation = useNavigation();
return (
<ScrollView>
{list?.map((item, index) => {
return (
<TouchableOpacity
style={{
borderRadius: sizes.radius,
overflow: 'hidden',
flexDirection: 'row',
}}
onPress={() => {
navigation.navigate('ProductDetails'), {productID: index};
}}>
.....
);
};
export default ProductItem;
MainNavigator
const Stack = createStackNavigator();
const MainNavigator = () => {
return (
<NavigationContainer>
<StatusBar hidden />
<Stack.Navigator>
<Stack.Screen
name="Root"
component={TabDrawer}
options={{
headerShown: false,
useNativeDriver: true,
gestureEnabled: false,
}}
/>
<Stack.Screen
name="ProductDetails"
component={productDetailScreen}
options={{headerShown: false}}
/>
</Stack.Navigator>
</NavigationContainer>
);
};
export default MainNavigator;
I tried to follow the Passing parameters to routes of react navigation without success
productDetail
I don't know where this error comes from can anyone explain to me specifically
Replace this navigation.navigate('ProductDetails'), {productID: index}; with below code:
navigation.navigate('ProductDetails',{productID: index})

How do I handle a combination of stack and page navigation?

I have a Bottom Tab Navigator that has two tabs. The Home tab contains a FlatList of objects. Once the user clicks on an object they should be routed to a page that contains the item that shouldn't show (as a tab) on the bottom tab, yet should show the bottom tab bar. My solution was to use a stack navigator in combination with a bottom tab navigator (shown below) as described in the official docs. However, when I nest the tab navigator inside of the stack navigator, it doesn't display the tab bar on the stack page. The other way around (stack navigator inside the tab navigator) I get an extra tab with the page, which is also an unwanted result.
I must be missing something. If anyone has a better way to route to an item in a list I'd like to hear it as well.
HomeStack (Stack Navigator) with the page Screen:
import { createStackNavigator } from "#react-navigation/stack";
import { ListItem } from "../components/ListItem/ListItem";
export default function StackNavigator() {
const Stack = createStackNavigator();
return (
<Stack.Navigator
screenOptions={{ headerShown: false }}
>
<Stack.Screen name="ListItem" component={ListItem} />
</Stack.Navigator>
);
}
TabsNavigator (BottomTabs) with HomeStack nested in side of it:
import { createBottomTabNavigator } from "#react-navigation/bottom-tabs";
import { Home } from "../screens/Home";
import { History } from "../screens/History";
import { FontAwesomeIcon } from "#fortawesome/react-native-fontawesome";
import { faList } from "#fortawesome/free-solid-svg-icons/faList";
import { faClockRotateLeft } from "#fortawesome/free-solid-svg-icons/faClockRotateLeft";
import HomeStack from "./HomeStack";
export default function TabsNavigator() {
const Tab = createBottomTabNavigator();
return (
<Tab.Navigator screenOptions={{ headerShown: false }}>
<Tab.Screen
name="List"
component={Home}
options={{
tabBarIcon: ({ focused }) => (
<FontAwesomeIcon
icon={faList}
style={{ color: focused ? "#317bc1" : "#CCC" }}
/>
),
}}
/>
<Tab.Screen
name="History"
component={History}
options={{
tabBarIcon: ({ focused }) => (
<FontAwesomeIcon
icon={faClockRotateLeft}
style={{ color: focused ? "#317bc1" : "#CCC" }}
/>
),
}}
/>
<Tab.Screen name="ListItem" component={HomeStack} />
</Tab.Navigator>
);
}
App:
import { StyleSheet, View } from "react-native";
import { Provider } from "react-redux";
import configureStore from "./src/redux";
import { NavigationContainer } from "#react-navigation/native";
import Navigator from "./src/routes/TabsNavigator";
export default function App() {
return (
<Provider store={configureStore()}>
<View style={{ flex: 1 }}>
<NavigationContainer>
<Navigator />
</NavigationContainer>
</View>
</Provider>
);
}
Take a reference from this code :
I've just now verified it, fine for me. Go through this code for proper understanding -
import * as React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
function HomeScreen(props) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text onPress={() => props.navigation.navigate('NextScreen')}>Home!</Text>
</View>
);
}
function NextScreen(props) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text onPress={() => props.navigation.navigate('NextScreen2')}>Next!</Text>
</View>
);
}
function NextScreen2(props) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text onPress={() => props.navigation.navigate('NextScreen3')}>Next2!</Text>
</View>
);
}
function NextScreen3(props) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text onPress={() => props.navigation.navigate('HomeScreen')}>Next3!</Text>
</View>
);
}
function SettingsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
</View>
);
}
const Tab = createBottomTabNavigator();
const stack = createNativeStackNavigator();
const StackNavigator = () => {
return <stack.Navigator option={{headerShown: false}}>
<stack.Screen name="HomeScreen" component={HomeScreen}/>
<stack.Screen name="NextScreen" component={NextScreen}/>
<stack.Screen name="NextScreen2" component={NextScreen2}/>
<stack.Screen name="NextScreen3" component={NextScreen3}/>
</stack.Navigator>
}
function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={StackNavigator} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<MyTabs />
</NavigationContainer>
);
}
As per your code change your HomeStack (Stack Navigator) likewise: -
import { createStackNavigator } from "#react-navigation/stack";
import { ListItem } from "../components/ListItem/ListItem";
import { Home } from '...<PATH TO HOME SCREEN>...';
const Stack = createStackNavigator();
export default function StackNavigator() {
return (
<Stack.Navigator
screenOptions={{ headerShown: false }}
>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="ListItem" component={ListItem} />
</Stack.Navigator>
);
}
Then change your first Tab likewise : -
<Tab.Screen
name="List"
component={HomeStack}
options={{
tabBarIcon: ({ focused }) => (
<FontAwesomeIcon
icon={faList}
style={{ color: focused ? "#317bc1" : "#CCC" }}
/>
),
}}
/>

TypeError: text.toLowerCase is not a function. (In 'text.toLowerCase()', 'text.toLowerCase' is undefined)

I am doing a project using MERN STACK in this I faced the above error.
ProductContainer.js
import React, { useState, useEffect } from 'react'
import { View, StyleSheet, ActivityIndicator, FlatList, Text} from 'react-native'
import { Container, Header, Icon, Item, Input } from 'native-base';
import ProductList from './ProductList';
import SearchedProduct from './SearchedProducts';
const data = require('../../assets/data/products.json');
const ProductContainer = () => {
const [products, setProducts ] = useState([]);
const [productsFiltered, setProductsFiltered] = useState([]);
const [focus, setFocus] = useState();
useEffect(() => {
setProducts(data);
setProductsFiltered(data);
setFocus(false);
return () => {
setProducts([])
setProductsFiltered([])
setFocus()
}
}, [])
const SearchProduct = (text) => {
setProductsFiltered(
products.filter((i) => i.name.toLowerCase().includes(text.toLowerCase()))
);
};
const openList = () => {
setFocus(true);
};
const onBlur = () => {
setFocus(flase);
};
return (
<Container>
<View style = {{ flexDirection: "row"}}>
<Input
width = "100%"
variant = "rounded"
placeholder="Search"
onFocus={openList}
onChangeText={(text) => SearchProduct(text)}
/>
</View>
{focus == true ? (
<SearchProduct
productsFiltered={productsFiltered}
/>
) : (
<View style={styles.container}>
<Text>Product Container</Text>
<View style={styles.listContainer}>
<FlatList
data={products}
numColumns={2}
renderItem={({item}) => <ProductList
key={item.brand}
item={item}/>}
keyExtractor={item => item.brand}
/>
</View>
</View>
)}
</Container>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
export default ProductContainer
SearchedProducts.js
import React from 'react';
import { View, StyleSheet, Dimensions} from 'react-native'
import { Content, Left, Body, ListItem, Thumbnail, Text } from 'native-base';
const SearchedProduct = (props) => {
const { productsFiltered } = props;
return(
<Content >
{productsFiltered.length > 0 ? (
productsFiltered.map((item) => (
<ListItem
key={item._id.$oid}
avatar
>
<Left>
<Thumbnail
source={{uri: item.image ?
item.image : 'https://cdn.pixabay.com/photo/2012/04/01/17/29/box-23649_960_720.png'
}}
/>
</Left>
<Body>
<Text>{item.name}</Text>
<Text note>{item.description}</Text>
</Body>
</ListItem>
))
) : (
<View style={styles.center}>
<Text style={{ alignSelf: 'center' }}>
No products match the selected criteria
</Text>
</View>
)}
</Content>
);
};
const styles = StyleSheet.create({
center: {
justifyContent: 'center',
alignItems: 'center',
height: 100
}
})
export default SearchedProduct;
Please can anyone help me to solve this error .If you want I will provide other details of my code.
Thanks in advance
Not sure but you are using SearchProduct name as a component and at the same time as a method. Maybe try to rename changing either component name or method name to see if it works.

Too much space between the appbar and status bar

I am making an app, where I want to use react navigation.
For some reason, whenever I use drawers in react navigation, there is a huge space between the status bar and the drawer app bar.
Here is my code for the ho -
import { StatusBar } from "expo-status-bar";
import * as React from "react";
import { useState, useEffect } from "react";
import { StyleSheet, Text, View, ScrollView } from "react-native";
import Constants from "expo-constants";
import Header from "../Header";
import { Flexbox } from "../Layout";
import Card from "../Card";
import { marginAboveCard } from "../../constants/constants";
import Row from "../Row";
import { convertToIndianNumberingFormat } from "../../utils/utils";
const HomeScreen = ({ navigation }) => {
const [cardsData, setCardsData] = useState({
confirmed: 0,
active: 0,
recovered: 0,
deceased: 0,
tests: 0,
critical: 0,
});
const [lastUpdated, setLastUpdated] = useState("");
useEffect(() => {
const getData = async () => {
const cardsDataResponse = await fetch(
"https://disease.sh/v3/covid-19/all"
);
const cardsDataFetched = await cardsDataResponse.json();
setCardsData({
confirmed: convertToIndianNumberingFormat(
cardsDataFetched.cases
),
active: convertToIndianNumberingFormat(cardsDataFetched.active),
recovered: convertToIndianNumberingFormat(
cardsDataFetched.recovered
),
deceased: convertToIndianNumberingFormat(
cardsDataFetched.deaths
),
tests: convertToIndianNumberingFormat(cardsDataFetched.tests),
critical: convertToIndianNumberingFormat(
cardsDataFetched.critical
),
});
const time = new Date(cardsDataFetched.updated);
const lastupdated = time.toLocaleTimeString();
setLastUpdated(`Last updated at ${lastupdated}`);
};
getData();
}, []);
return (
<ScrollView style={styles.main}>
<View style={{ marginTop: Constants.statusBarHeight }}>
<StatusBar style="auto" />
<Header text="COVID-19" />
<Text style={styles.lastUpdatedText}>{lastUpdated}</Text>
<View style={{ marginTop: marginAboveCard }}>
<Flexbox style={{ marginTop: 15 }}>
<Card
background="red"
title="Confirmed"
number={cardsData.confirmed}
/>
<Card
background="#3877F0"
title="Active"
number={cardsData.active}
/>
</Flexbox>
<Flexbox style={{ marginTop: marginAboveCard }}>
<Card
background="#47CC3C"
title="Recovered"
number={cardsData.recovered}
/>
<Card
background="#868686"
title="Deceased"
number={cardsData.deceased}
/>
</Flexbox>
<Flexbox style={{ marginTop: marginAboveCard }}>
<Card
background="#E85FEB"
title="Tests"
number={cardsData.tests}
/>
<Card
background="#5BF8B6"
title="Critical"
number={cardsData.critical}
/>
</Flexbox>
</View>
<View style={{ marginTop: 30 }}>
<Header text="TABLE STATISTICS" />
</View>
</View>
</ScrollView>
);
};
export default HomeScreen;
const styles = StyleSheet.create({
main: {
flex: 1,
backgroundColor: "#000232",
},
lastUpdatedText: {
color: "white",
textAlign: "center",
marginTop: 12,
fontSize: 15,
},
});
My app.jsx -
import * as React from "react";
import HomeScreen from "./components/screens/HomeScreen";
import VaccineScreen from "./components/screens/VaccineScreen";
import { NavigationContainer } from "#react-navigation/native";
import { createDrawerNavigator } from "#react-navigation/drawer";
const Drawer = createDrawerNavigator();
export default function App() {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Vaccine" component={VaccineScreen} />
</Drawer.Navigator>
</NavigationContainer>
);
}
If you look at the code of home screen properly, you would see a status style component which is set to auto. Even after removing it, the space is there. There are no errors in the console of any sort. This error started coming when I used react navigation drawer. Is there a way I can remove the space?
Did you try to move StatusBar as top most child like my sample below?
....
<View>
<StatusBar style="auto" />
<ScrollView style={styles.main}>
<View style={{ marginTop: Constants.statusBarHeight }}>
...
How you define the header title and the drawer icon?

React Native : how to make context available from App to a Screen when using react navigation?

I am new to RN and try to make a login system, I am storing the email and password (hidden for the sake of brievity of the code) in a global scope in order to use a component to make a call to the server, in short I am trying to keep the email at the App level, and avoid passing from screen to screen.
function App() {
const [email, setEmail] = React.useState('')
const [token,setToken] = React.useState(null)
const AuthenticationContext = React.createContext();
return (
<AuthenticationContext.Provider value={{email,setEmail}}>
<NavigationContainer>
<Stack.Navigator>
>
{token == null ? (
<Stack.Screen name="Home" component={HomeScreen} />
) : (
<Stack.Screen
name="Profile"
component={ProfileScreen}
options={({ route }) => ({ title: route.params.name })}
/>
)}
</Stack.Navigator>
</NavigationContainer>
</AuthenticationContext.Provider>
);
}
And HomeScreen and the LoginForm component which is a grandchild of App component (in which I will set the token):
function HomeScreen({ navigation, route },props ) {
return (
<AuthenticationContext.Consumer>
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<LoginForm {...props} />
{ props.token != null ?
<Button
title="Go to Profile"
onPress={() => navigation.navigate('Profile')}
/>
: null}
</View>
</AuthenticationContext.Consumer>
);
}
However I get the message : AuthenticationContext is not defined
Create the context variable outside of App and make it exportable.
export const AuthenticationContext = React.createContext();
function App() {
return (
<AuthenticationContext.Provider value={{email,setEmail}}>
// Children
</AuthenticationContext.Provider>
)
}
Then on HomeScreen you can use it in the following way
With the useContext hook:
import { AuthenticationContext } from './App';
function HomeScreen (props) => {
const { email, setEmail } = React.useContext(AuthenticationContext);
const onPress = () => {
props.navigation.navigate('Profile');
}
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<LoginForm {...props} />
{ props.token != null ? (
<Button
title="Go to Profile"
onPress={onPress}
/>
) : null
}
</View>
)
}
Or without
import { AuthenticationContext } from './App';
function HomeScreen (props) => {
const onPress = () => {
props.navigation.navigate('Profile');
}
return (
<AuthenticationContext.Consumer>
{({ email, setEmail }) => (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<LoginForm {...props} />
{ props.token != null ? (
<Button
title="Go to Profile"
onPress={onPress}
/>
) : null
}
</View>
}
</AuthenticationContext.Consumer>
)
}

Resources