Getting a modal to be behind tabNavigator using Modlize alwaysOpen - javascript

So I'm pretty new to programming and while making my first React Native project I got stuck trying to create a modal that's always open behind the bottom nav (The reason I want it that way is for it to be like a cart where whenever the user adds something it'll slightly nudge up to show something new was added), I did manage to get the modal behind the tab but now the bottom tab is unresponsive, does anyone have a fix for this?
my app.js
import React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import Header from './components/Header';
import RootStack from './components/RootStack';
const App = () => {
return (
<>
<Header />
<NavigationContainer>
<RootStack />
</NavigationContainer>
</>
);
};
export default App;
RootStack:
import React from 'react'
import { createStackNavigator } from '#react-navigation/stack'
import CarrinhoModal from '../CarrinhoModal'
import TabNavigator from '../TabNavigator';
const StackNavigation = createStackNavigator();
const RootStack = () => {
return (
<>
<StackNavigation.Navigator headerMode='none' >
<StackNavigation.Screen name='Tab' component={TabNavigator} />
<StackNavigation.Screen name='Carrinho' getComponent={CarrinhoModal} />
</StackNavigation.Navigator>
</>
)
}
export default RootStack;
TabNavigator:
import React from 'react';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import Home from '../../pages/Home'
import Perfil from '../../pages/Perfil'
import CarrinhoModal from '../CarrinhoModal';
const Tab = createBottomTabNavigator();
const TabNavigator = ({ navigation }) => {
return (
<>
<Tab.Navigator
initialRouteName="Home"
tabBarOptions={{
activeTintColor: 'white',
inactiveTintColor: 'gray',
activeBackgroundColor: '#1E4B75',
inactiveBackgroundColor: '#1E4B75'
}}
>
{/* <Tab.Screen
name='Carrinho'
component={CarrinhoModal}
listeners={( navigation ) => ({
tabPress: e => {
e.preventDefault();
navigation.navigate(CarrinhoModal)
}
})}
/> */}
<Tab.Screen name='Home' component={Home} />
<Tab.Screen name='Perfil' component={Perfil} />
</Tab.Navigator>
<CarrinhoModal />
</>
)
}
export default TabNavigator;
CarrinhoModal:
import React, { useRef } from 'react'
import { Modalize } from 'react-native-modalize';
import Carrinho from '../../pages/Carrinho';
const CarrinhoModal = (props) => {
return (
<>
<Modalize
ref={props.modalRef}
alwaysOpen={75}
modalHeight={400}
handlePosition='inside'
>
<Carrinho />
</Modalize>
</>
)
}
export default CarrinhoModal;
As I said I'm pretty new in all this so if you could point me in the right direction it would be much apreciated!

Related

Navigate to another StackNavigtor screen on button press React Native

I have made a Main Navigator in which I have made 2 sub navigators:
This is my MainNavigator:
import React, {useEffect, useState} from 'react';
import {createStackNavigator} from '#react-navigation/stack';
import storage from '../services/storage';
import {useDispatch, useSelector} from 'react-redux';
import {setUser} from '../store/reducers/auth';
import AuthNavigation from './AuthNavigation';
import MainNavigation from './MainNavigation';
const {Navigator, Screen} = createStackNavigator();
const StackNavigation = () => {
const [isLogged, setIsLogged] = useState(false);
const dispatch = useDispatch();
const loadUser = async () => {
try {
const data = await storage.get('USER');
if (data !== null && data !== '') {
console.log('Hello user', data);
dispatch(setUser(data));
setIsLogged(true);
}
} catch (error) {
console.log('APP JS ERROR', error.message);
}
};
useEffect(() => {
loadUser();
}, []);
return (
<Navigator screenOptions={{headerShown: false}}>
{isLogged ? (
<Screen name="MainNavigation" component={MainNavigation} />
) : (
<Screen name="AuthNavigation" component={AuthNavigation} />
)}
</Navigator>
);
};
export default StackNavigation;
These are my sub navigators:
AuthNavigation:
import React from 'react';
import {createStackNavigator} from '#react-navigation/stack';
import SignUpScreen from '../screens/AccountScreens/SignUpScreen';
import LoginScreen from '../screens/AccountScreens/LoginScreen';
import ForgotPassword from '../screens/AccountScreens/ForgotPassword';
import OTPVerification from '../screens/AccountScreens/OTPVerification';
import SetNewPassword from '../screens/AccountScreens/SetNewPassword';
const {Navigator, Screen} = createStackNavigator();
const AuthNavigation = () => {
const verticalAnimation = {
gestureDirection: 'vertical',
cardStyleInterpolator: ({current, layouts}) => {
return {
cardStyle: {
transform: [
{
translateY: current.progress.interpolate({
inputRange: [0, 1],
outputRange: [layouts.screen.height, 0],
}),
},
],
},
};
},
};
return (
<Navigator
initialRouteName={'Login'}
screenOptions={{headerShown: false, animationEnabled: true}}>
<Screen
name="SignUp"
component={SignUpScreen}
options={verticalAnimation}
/>
<Screen name="Login" component={LoginScreen} />
<Screen name="ForgotPassword" component={ForgotPassword} />
<Screen name="OTPVerification" component={OTPVerification} />
<Screen name="SetNewPassword" component={SetNewPassword} />
</Navigator>
);
};
export default AuthNavigation;
MainNavigation:
import React, {useState} from 'react';
import {createStackNavigator} from '#react-navigation/stack';
import MyTabNavigation from './MyTabNavigation';
import GymDetailScreen from '../screens/InnerScreens/GymDetailScreen';
import AccountOverview from '../screens/DrawerScreens/AccountOverview';
import SubscriptionDetails from '../screens/DrawerScreens/SubscriptionDetails';
import BillingDetails from '../screens/DrawerScreens/BillingDetails';
import ChangePassword from '../screens/DrawerScreens/ChangePassword';
import BuySubscribtion from '../screens/InnerScreens/BuySubscribtion';
import ScanScreen from '../screens/InnerScreens/ScanScreen';
import PaymentSummary from '../screens/InnerScreens/PaymentSummary';
import PaymentMethod from '../screens/InnerScreens/PaymentMethod';
const {Navigator, Screen} = createStackNavigator();
const MainNavigation = () => {
const horizontalAnimation = {
cardStyleInterpolator: ({current, layouts}) => {
return {
cardStyle: {
transform: [
{
translateX: current.progress.interpolate({
inputRange: [0, 1],
outputRange: [layouts.screen.width, 0],
}),
},
],
},
};
},
};
return (
<Navigator
initialRouteName={'MyTabNavigation'}
screenOptions={{headerShown: false, animationEnabled: true}}>
<Screen name="GymDetailScreen" component={GymDetailScreen} />
<Screen
name="MyTabNavigation"
component={MyTabNavigation}
options={horizontalAnimation}
/>
<Screen name="AccountOverview" component={AccountOverview} />
<Screen name="SubscriptionDetails" component={SubscriptionDetails} />
<Screen name="BillingDetails" component={BillingDetails} />
<Screen name="ChangePassword" component={ChangePassword} />
<Screen name="BuySubscription" component={BuySubscribtion} />
<Screen name="ScanScreen" component={ScanScreen} />
<Screen name="PaymentSummary" component={PaymentSummary} />
<Screen name="PaymentMethod" component={PaymentMethod} />
</Navigator>
);
};
export default MainNavigation;
I want to go to MainNavigator on Login which is in AuthNavigator, Here is how I am doing this:
navigation.navigate('MainNavigation');
But its giving me this error:
The action 'NAVIGATE' with payload {"name":"MainNavigation"} was not handled by any navigator.
Do you have a screen named 'MainNavigation'?
If you're trying to navigate to a screen in a nested navigator, see https://reactnavigation.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator.
This is a development-only warning and won't be shown in production.
Please help me with this coz I am trying this for the first time. Thanks in advance
You are using Authentication flows stated in React Navigation documents.
Please be noted that this approach using conditionally rendering screens which means screen is not rendered if condition is not fulfilled. So, application will cause error for navigation to non-existing screen.
What you need to do in order to jump to MainNavigation screen, is to set your
isLogged variable in MainNavigator to true.
navigation.navigate('MainNavigation');
Here you can not use navigate method because both are different Navigators
So you have to render your navigator on a Conditional base.
For ex:
you can save authTocken after Successful Login and in your main Route file
you can check write condition whether authTocken is null or not.
On that basis you can render your navigator Like,
{
authTocken != '' (
<Stack.Navigator screenOptions={{ headerShown: false }} initialRouteName={initialRoute}>
<Stack.Screen name={routes.Dasboard} component={Dashboard} />
<Stack.Screen name={routes.Setting} component={Setting} />
</Stack.Navigator>
)
:
<Stack.Navigator screenOptions={{ headerShown: false }}
initialRouteName={initialRoute}>
<Stack.Screen name={routes.Login} component={Login} />
<Stack.Screen name={routes.Registration} component=Registration} />
</Stack.Navigator>
}

Problem with React 5 Auth Screen navigation and Redux Store

I'm new to react native and I'm having this problem with Auth Screen navigation and Redux Store.
So when I press "Start" it doesn't navigate to ClassesListScreen but remain in the LoginScreen. Although when I console log it print out that the "isLoggedIn" property in Store is true but it still doesn't re-render. Why is that happening? Thank you very much.
Here's my StackNavigation.js:
import React from 'react'
import { createStackNavigator } from '#react-navigation/stack';
import StudentsTabNavInit from './StudentsTabNavigation';
import LoginScreen from '../components/login/LoginScreen';
import DetailsScreen from '../components/details/DetailsScreen';
import store from '../store/store'
import AddScreen from '../components/add/AddScreen';
import ClassesListScreen from '../components/classes/ClassesListScreen';
const StackNav = createStackNavigator();
import { connect } from 'react-redux'
function StackNavInit(){
return (
<StackNav.Navigator
initialRouteName="Login"
>
{store.getState().isLoggedIn? (
<>
<StackNav.Screen
name="Classes"
component={ClassesListScreen}
options={{title: "Your Classes"}}
/>
<StackNav.Screen
name="StudentsTabNav"
component={StudentsTabNavInit}
options ={{title: "Students"}}
/>
<StackNav.Screen
name="Details"
component={DetailsScreen}
options={{ title: "Details" }}
/>
<StackNav.Screen
name="Add"
component={AddScreen}
options={{title: "Add Course"}}
/>
</>
) : (
<>
<StackNav.Screen
name="Login"
component={LoginScreen}
options={{headerShown: false}}
/>
</>
)
}
</StackNav.Navigator>
)
}
export default StackNavInit
My LoginScreen.js:
import React from 'react'
import { render } from 'react-dom'
import { Text, View, Button} from 'react-native'
import store from '../../store/store'
import {login} from '../../store/actions'
class LoginScreen extends React.Component{
constructor(props){
super(props)
}
logIn = ()=> {
//console.log(store.getState().isLoggedIn)
store.dispatch(login());
//this.props.navigation.navigate("Classes")
};
render(){
return (
<View>
<Text> Welcome to Courses Managing Application</Text>
<Text> Press Start </Text>
<Button title="Start" onPress={this.logIn}></Button>
<Text> {store.getState().isLoggedIn} </Text>
</View>
)
}
}
export default LoginScreen
for further information, here are things in my store folder (But I don't think it's related):
actions.js:
export const UPDATE_INFOR = 'UPDATE_INFOR'
export const GET_DATA = 'GET_DATA'
export const ADD_EMPLOYEE = 'ADD_EMPLOYEE'
export const DATA_REQ_SENT = 'DATA_REQ_SENT'
export const DATA_REQ_SUCCEED = 'DATA_REQ_SUCCEED'
export const DATA_REQ_FAILED = 'DATA_REQ_FAILED'
export const LOG_IN = 'LOG_IN'
export const updateInfor = (infor) => ({type: UPDATE_INFOR, payload: infor})
export const addEmployee = (infor) => ({type: ADD_EMPLOYEE, payload: infor})
export const login = () => ({type: LOG_IN})
reducers.js:
import defaultState from './state'
function reducer(state = defaultState, action) {
switch (action.type) {
case 'LOG_IN':
return {...state, isLoggedIn: true}
default:
return state
}
}
export default reducer
state.js:
export default defaultState = {
isLoggedIn: false,
url: 'https://randomuser.me/api/',
results: 100,
nat:'us',
list_inc:'name,gender,dob,phone,picture,id',
}
store.js:
import { createStore, applyMiddleware } from 'redux'
import reducer from './reducers'
import thunk from 'redux-thunk'
export default store = createStore(reducer, applyMiddleware(thunk))
I figured out a way my self.
First wrap the App with the <Provider></Provider>
export default function App() {
return (
<Provider store ={store}>
<NavigationContainer>
<StackNavInit/>
</NavigationContainer>
</Provider>
);
}
then in StackNav use a Selector to connect a property isLoggedin to the store property with the same name, eg: const isLoggedIn = useSelector(state => state.isLoggedIn)
then the Navigator gonna look like:
function StackNavInit(){
const isLoggedIn = useSelector(state => state.isLoggedIn)
return (
<StackNav.Navigator
initialRouteName="Login"
>
{isLoggedIn? (
<>
<StackNav.Screen
name="Classes"
component={ClassesListScreen}
options={{title: "Your Classes"}}
/>
<StackNav.Screen
name="StudentsTabNav"
component={StudentsTabNavInit}
options ={{title: "Students"}}
/>
<StackNav.Screen
name="Details"
component={DetailsScreen}
options={{ title: "Details" }}
/>
<StackNav.Screen
name="Add"
component={AddScreen}
options={{title: "Add Course"}}
/>
</>
) : (
<>
<StackNav.Screen
name="Login"
component={LoginScreen}
options={{headerShown: false}}
/>
</>
)
}
</StackNav.Navigator>
)
}

Navigate Between Screen React Native

I'm coming from ReactJS and a bit confused about how to navigate between screens in react native.
I'm using these react-navigation and react-navigation-stack versions:
"#react-navigation/native": "^5.8.10", "#react-navigation/stack": "^5.12.8"
So I have 2 screens already:
SplashScreenContainer
import React from 'react';
import {Text, View} from "react-native-reanimated";
class SplashScreenContainer extends React.PureComponent {
redirectToHome = () => {
const {navigation} = this.props;
navigation.navigate('HomeContainer');
}
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text onPress={() => this.redirectToHome}>
Splash Screen
</Text>
</View>
)
}
}
export default SplashScreenContainer;
HomeScreenContainer
import React from 'react';
import {Text, View} from "react-native-reanimated";
class HomeScreenContainer extends React.PureComponent {
render() {
return (
<View>
<Text>Home Screen</Text>
</View>
)
}
}
export default HomeScreenContainer;
and here's my app js to render the screens inside NavigationContainer:
App.js
import React from 'react';
import {SafeAreaView} from "react-native-safe-area-context";
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
const SplashScreenContainer = React.lazy(() => import('./app/containers/SplashScreenContainer'));
const HomeContainer = React.lazy(() => import('./app/containers/HomeContainer'));
const Stack = createStackNavigator();
class App extends React.PureComponent {
render() {
return (
<SafeAreaView>
<NavigationContainer>
<Stack.Navigatior>
<Stack.Screen name='SplashScreenContainer' component={() => <SplashScreenContainer {...this.props} />}/>
<Stack.Screen name='HomeContainer' component={() => <HomeContainer {...this.props} />}/>
</Stack.Navigatior>
</NavigationContainer>
</SafeAreaView>
)
}
}
export default App;
After I run with npm run ios command, the console gives me this error:
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
I don't understand what is this error about, what am I missing here? how can I navigate between the screens in react-native?
Any help will be much appreciated.
Thank You.
Regards
Well, I made it works. Here are the changes I made:
Remove SafeAreaView from App.js
Add {Suspense} in App.js because I forgot that React.lazy depends on Suspense
Use SafeAreaView in Home and SplashScreen imported from 'react-native'
App.js
import React, {Suspense} from 'react';
import {SafeAreaView, Text} from 'react-native';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
const SplashScreenContainer = React.lazy(() => import('./app/containers/SplashScreenContainer'));
const HomeContainer = React.lazy(() => import('./app/containers/HomeContainer'));
const Stack = createStackNavigator();
const Loading = () => {
return (
<SafeAreaView>
<Text>Loading</Text>
</SafeAreaView>
)
};
const Routes = () => {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName='SplashScreenContainer'>
<Stack.Screen
name='SplashScreenContainer'
component={SplashScreenContainer}
options={{ headerShown: false }}
/>
<Stack.Screen
name='HomeContainer'
component={HomeContainer}
options={{ headerShown: false }}
/>
</Stack.Navigator>
</NavigationContainer>
)
}
class App extends React.PureComponent {
render() {
return (
<Suspense fallback={<Loading/>}>
<Routes/>
</Suspense>
)
}
}
export default App;
SplashScreenContainer.js
import React from 'react';
import {Button, SafeAreaView} from 'react-native';
class SplashScreenContainer extends React.PureComponent {
constructor(props) {
super(props);
}
redirectToHome = () => {
const {navigation} = this.props;
navigation.navigate('HomeContainer');
};
render() {
return (
<SafeAreaView style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Button onPress={() => this.redirectToHome()} title='Go To Home Screen'/>
</SafeAreaView>
)
}
}
export default SplashScreenContainer;
HomeScreenContainer.js
import React from 'react';
import {Button, SafeAreaView} from 'react-native';
class HomeContainer extends React.PureComponent {
redirectToSplash = () => {
const {navigation} = this.props;
navigation.navigate('SplashScreenContainer');
};
render() {
return (
<SafeAreaView style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Button onPress={() => this.redirectToSplash()} title='Go To Splash Screen'/>
</SafeAreaView>
)
}
}
export default HomeContainer;
Everything's working now, I'm able to switch between SplashScreen and HomeScreen when button is clicked/tapped.

React Native: Using navigation with dynamic components mapped to arrays

I am building an app in which several of the screens have dynamically rendered cards which are mapped to an array of objects called ENTRIES. Each one of these cards can be pressed to navigate to a corresponding screen, however I cannot seem to get the navigation to work.
I keep getting the following error Error: You need to specify name or key when calling navigate with an object as the argument.
I am passing is the screen value from ENTRIES into my this.props.navigation.navigate, which should direct to that screen when the <TouchableOpacity> is pressed.
Here is an an example of the code below:
App.js File
import React from 'react;
import {createMaterialBottomTabNavigator} from '#react-navigation/material-bottom-tabs';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import Home from './src/screens/Home';
import SettingsScreen from './src/screens/SettingsScreen';
import PrivacyScreen from './src/screens/PrivacyScreen';
import NotificationsScreen from './src/screens/NotificationsScreen';
import SoundsScreen from './src/screens/SoundsScreen';
import ThemeScreen from './src/screens/ThemeScreen';
const PrivacyStack = createStackNavigator();
const SettingsStack = createStackNavigator();
const AuthStack = createStackNavigator();
const MainStack = createStackNavigator();
const Tabs = createMaterialBottomTabNavigator();
const TabNavigator = () => {
return (
<Tabs.Navigator
initialRouteName="Home"
<Tabs.Screen
name="Home"
component={HomeStack}
/>
Tabs.Screen
name="Settings"
component={SettingsStack}
children={this.SettingsStack}
</Tabs.Navigator>
)
}
const AuthStack = () => (
<AuthStack.Navigator>
<AuthStack.Screen
name="Auth"
component={Auth}
/>
</AuthStack.Navigator>
);
const SettingsStackScreen = () => (
<SettingsStack.Navigator>
<SettingsStack.Screen
name="Settings"
component={Settings}
/>
<SettingsStack.Screen
name="Privacy"
component={PrivacyStack}
/>
<SettingsStack.Screen
name="Theme"
component={ThemeScreen}
/>
<SettingsStack.Screen
name="Notifications"
component={NotificationsScreen}
/>
<SettingsStack.Screen
name="Sound"
component={SoundsScreen}
/>
</SettingsStack.Navigator>
);
const PrivacyStack = () => (
<PrivacyStack.Navigator>
<PrivacyStack.Screen
name="Privacy"
component={PrivacyScreen}
/>
<PrivacyStack.Screen
name="Notifications"
component={NotificationsScreen}
/>
</PrivacyStack.Navigator>
);
const App = () => {
return (
<NavigationContainer ref={navigationRef}>
<MainStack.Navigator>
<MainStack.Screen name="Tabs" component={TabNavigator} />
<MainStack.Screen
name="Auth"
component={AuthStack}
options={{gestureEnabled: false}}
/>
</MainStack.Navigator>
</NavigationContainer>
)
}
Settings.js File
import React, {Component} from 'react';
import {TouchableOpacity, ScrollView} from 'react-native;
export default class Settings extends Component {
render(screen, index) {
return (
<ScrollView>
{ENTRIES.map((entry, index) => (
<TouchableOpacity
key={entry.index}
onPress={() => this.props.navigation.navigate(screen)}>
</TouchableOpacity>
))}
</ScrollView>
)
}
export default Settings
entries.js File
import React from 'react';
export const ENTRIES = [
{
name: "Theme",
screen: "ThemeScreen",
},
{
name: "Sounds",
screen: "SoundsScreen",
},
{
name: "Notifications",
screen: "NotificationsScreen",
},
]
The render function does not take any arguments. And the screen in your array should be accessed by using the entry.screen
render() {
return (
<ScrollView>
{ENTRIES.map((entry, index) => (
<TouchableOpacity
key={entry.name}
onPress={() => this.props.navigation.navigate(entry.screen)}>
</TouchableOpacity>
))}
</ScrollView>
)
}

How to use react hooks on react-native with react-navigation

This is App.js using react-navigation. There are two screens on it called HomeScreen and AddScreen.
import * as React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import HomeScreen from './src/HomeScreen';
import AddScreen from './src/AddScreen';
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Add" component={AddScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
And This is home Screen. There is a 'items' in 'useState. It is gived through Add by navigation as props.
import * as React from 'react';
import PropTypes from 'prop-types';
import { View, Text, Button } from 'react-native';
function HomeScreen({ navigation, route }) {
const [items, setItems] = React.useState([]);
React.useEffect(() => {
if (route.params?.items) {
// Post updated, do something with `route.params.post`
// For example, send the post to the server
console.log('saved');
}
}, [route.params?.items]);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
title="Create post"
onPress={() => navigation.navigate('Add', { items, setItems })}
/>
<View>
{items.map((item, i) => {
return (
<View>
<Text>{item.itemName}</Text>
<Text>{item.itemPrice}</Text>
</View>
);
})}
</View>
</View>
);
}
HomeScreen.propTypes = {
navigation: PropTypes.object.isRequired,
};
export default HomeScreen;
And AddScreen receives 'items' as route.params.
And it use 'setItems' to push his own data in it.
After adding, navigation return to HomeScreen with items that is added with new item.
import * as React from 'react';
import PropTypes from 'prop-types';
import { View, Text, Button, TextInput } from 'react-native';
function AddScreen({ route, navigation }) {
const { items, setItems } = route.params;
const [itemName, setItemName] = React.useState('');
const [itemPrice, setItemPrice] = React.useState('0');
const addItem = () => {
setItems([...items, { itemName, itemPrice }]);
setItemName('');
setItemPrice('0');
};
return (
<View>
<TextInput
multiline
placeholder="What's on your mind?"
value={itemName}
onChangeText={setItemName}
/>
<TextInput
multiline
placeholder="What's on your mind?"
value={itemPrice}
onChangeText={setItemPrice}
/>
<Button
title="Done"
onPress={() => {
addItem();
// Pass params back to home screen
navigation.navigate('Home', items);
}}
/>
</View>
);
}
AddScreen.propTypes = {
navigation: PropTypes.object.isRequired,
route: PropTypes.object.isRequired,
};
export default AddScreen;
It works well on my purpose.
But I'm not sure whether this way is correct or not using react hooks to give and receive data from parent to child.
Could you modify my code ?
You should consider using React Context API https://uk.reactjs.org/docs/context.html. Its dedicated to sharing the common state (items in your case). Here is an example:
You should create a common context for items:
ItemsState.js
import React, { useState, useContext } from 'react';
const ItemsContext = React.createContext([]);
export const ItemsProvider = ({ children }) => {
return (
<ItemsContext.Provider value={useState([])}>
{children}
</ItemsContext.Provider>
);
}
export const useItems = () => useContext(ItemsContext);
Then share the context between screens with provider in App.js like this
import {ItemsProvider} from 'ItemsState';
function App() {
return (
<ItemsProvider> // share the items between both screens
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Add" component={AddScreen} />
</Stack.Navigator>
</NavigationContainer>
</ItemsProvider>
);
}
Then use items context in each screen like this AddScreen.js
import {useItems} from './ItemsState';
function AddScreen({ route, navigation }) {
const [items, setItems] = useItems(); // <- using items context as global useState
const [itemName, setItemName] = React.useState('');
const [itemPrice, setItemPrice] = React.useState('0');
const addItem = () => {
setItems([...items, { itemName, itemPrice }]);
setItemName('');
setItemPrice('0');
};
return (
<View>
<TextInput
multiline
placeholder="What's on your mind?"
value={itemName}
onChangeText={setItemName}
/>
<TextInput
multiline
placeholder="What's on your mind?"
value={itemPrice}
onChangeText={setItemPrice}
/>
<Button
title="Done"
onPress={() => {
addItem();
// Pass params back to home screen
navigation.navigate('Home', items);
}}
/>
</View>
);
}
You can also use useReducer hook and make more Redux-like. Check out this article
https://medium.com/simply/state-management-with-react-hooks-and-context-api-at-10-lines-of-code-baf6be8302c
in order to share data between components you can use Context API or Redux, passing full objects through navigation routes is an anti-pattern, you can find more information in the docs
https://reactnavigation.org/docs/params/#what-should-be-in-params

Categories