I'm trying to style my TabNavigator using Native Base, but I always get "props.navigation.navigate is not a function" and I have no idea why.
This is my TabNavigator:
import { createBottomTabNavigator } from 'react-navigation';
import React from 'react';
import { Button, Text, Icon, Footer, FooterTab } from 'native-base';
import CameraRouter from './CameraRouter';
import Feed from '../components/Feed';
const MainRouter = createBottomTabNavigator(
{
Feed: {
screen: Feed,
},
Camera: {
screen: CameraRouter,
navigationOptions: {
tabBarVisible: false,
},
},
},
{
tabBarComponent: props => {
return (
<Footer>
<FooterTab>
<Button
vertical
onPress={() => props.navigation.navigate('Feed')}
>
<Icon name="bowtie" />
<Text>Lucy</Text>
</Button>
<Button
vertical
onPress={() => props.navigation.navigate('CameraRouter')}
>
<Icon name="briefcase" />
<Text>Nine</Text>
</Button>
<Button
vertical
>
<Icon name="headset" />
<Text>Jade</Text>
</Button>
</FooterTab>
</Footer>
);
}
}
);
export default MainRouter;
Which I call here:
import React, { Component } from 'react';
import { YellowBox } from 'react-native';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import MainRouter from './config/MainRouter';
import reducers from './reducers';
YellowBox.ignoreWarnings(['Warning: isMounted(...) is deprecated', 'Module RCTImageLoader']);
class App extends Component {
render() {
const store = createStore(reducers);
return (
<Provider store={store}>
<MainRouter />
</Provider>
);
}
}
export default App;
What is wrong with my code? I used this guide to get an idea of the usage:
http://docs.nativebase.io/docs/examples/navigation/StackNavigationExample.html
Thank you guys!
if want to implement with react-navigation 3.0 with native-base 2.13 then below code will work.
import { createBottomTabNavigator,createStackNavigator,createAppContainer } from 'react-navigation';
import React from 'react';
import { Button, Text, Icon, Footer, FooterTab } from 'native-base';
import Home from './containers/Home';
import CreateCase from './containers/CreateCase';
import Profile from './containers/Profile';
import Performance from './containers/Performance';
const MainNavigator = createStackNavigator(
{
Home : {
screen: Home,
navigationOptions: {
header: null,
}
},
Create: {
screen: CreateCase,
navigationOptions: {
title: "Generate Case",
}
},
},
{
initialRouteName: "Home"
}
);
const Main = createBottomTabNavigator({
Home: { screen: MainNavigator },
Profile: { screen: Profile },
Performance: {screen: Performance}
},
{
tabBarComponent: props => {
return (
<Footer>
<FooterTab>
<Button
vertical
onPress={() => props.navigation.navigate('Home')}
>
<Icon name="bowtie" />
<Text>Lucy</Text>
</Button>
<Button
vertical
onPress={() => props.navigation.navigate('Profile')}
>
<Icon name="briefcase" />
<Text>Nine</Text>
</Button>
<Button
vertical
>
<Icon name="headset" />
<Text>Jade</Text>
</Button>
</FooterTab>
</Footer>
);
}
}
);
export default createAppContainer(Main);
https://reactnavigation.org/docs/en/navigation-prop.html
This doc mentions that navigation props is not available to every component by default only the screen components have it.
if you wish to access this prop in other components then you either pass this prop to the component where it is needed or you use what is called 'withNavigation'
I think the props aren't being passed through from your App component, could you try this?
class App extends Component {
render() {
const store = createStore(reducers);
return (
<Provider store={store}>
<MainRouter {...props}/>
</Provider>
);
}
}
export default App;
I found the solution to my problem: I had to add a root StackNavigator
Related
How I can re-render a web-view running inside a app built with react native. For exemple: The cart tab need to load the same url every time I click on it.
This is the cart class:
import React, { useState } from 'react';
import { ActivityIndicator, WebView, View, Button, ScrollView,
RefreshControl,
Text, } from 'react-native';
import Config from '../config';
export default class CarrinhoScreen extends React.Component {
reload() {
this.myWebView.reload()
}
render() {
return (
<>
<View style={{ flex: 1 }}>
<WebView
source={{ uri: 'https://www.genieshopp.com/checkout/cart/' }}
userAgent='bring-app'
startInLoadingState={true}
ref={(ref) => this.myWebView = ref}
/>
</View>
</>
)
}
};
Here is where the tabNavigator is created:
import React from 'react';
import { Platform } from 'react-native';
import { createStackNavigator, createBottomTabNavigator } from 'react-navigation';
import CarrinhoScreen from '../screens/CarrinhoScreen';
const config = Platform.select({
web: { headerMode: 'screen' },
default: {},
});
const CarrinhoStack = createStackNavigator(
{
Carrinho: CarrinhoScreen
},
config
);
CarrinhoStack.navigationOptions = {
tabBarLabel: 'Carrinho',
tabBarIcon: ({ focused }) => (
<TabBarIcon focused={focused} name={Platform.OS === 'ios' ? 'ios-cart' : 'md-cart'}/>
),
};
CarrinhoStack.path = '';
const tabNavigator = createBottomTabNavigator(
{
CarrinhoStack,
},
{
backBehavior: 'history'
}
);
tabNavigator.path = '';
export default tabNavigator;
I know there is the myWebView.reload(), but I want to know how I reload it when the bottom tab is switched or when I click on the same icon.
Solved by putting resetOnBlur: CarrinhoScreen after backBehavior: history
You can put any other screen you want to reset on there.
This is the structure of my navigation in which I have 3 components, and I have a sidemu (drawer), but I do not want the sidemenu to be seen in login, so I place the "Detail" component in the "LoginStack" . The sidemenu only is showed in Home component.
the behavior occurs of the gif, why can this happen?
usernavigation.js
import React from "react";
import { createAppContainer, createSwitchNavigator } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import { createDrawerNavigator } from "react-navigation-drawer";
import SideBar from "../components/SideBar/SideBar";
import { STYLES } from "../styles/Styles";
import LoginScreen from "../screens/Login/Login";
import HomeScreen from "../screens/Home/Home";
import DetailScreen from "../screens/DetailScreen/DetailScreen ";
//Aqui se debe incluir las screen que no deben mostrar el drawer
const LoginStack = createStackNavigator(
{
Login: {
screen: LoginScreen,
navigationOptions: {
title: "Login",
headerLeft: null,
header: null
}
},
Detail: {
screen: DetailScreen,
navigationOptions: {
title: "Detail container",
headerStyle: STYLES.bgHeaderBack,
headerTintColor: "#fff",
headerMode: "none"
}
}
},
{
initialRouteName: "Login"
}
);
const HomeStack = createStackNavigator(
{
Home: {
screen: HomeScreen,
navigationOptions: {
title: "Home",
headerLeft: null,
header: null
}
}
},
{
initialRouteName: "Home",
headerMode: "none"
}
);
const DrawerStack = createDrawerNavigator(
{
Home: {
screen: HomeStack
}
},
{
contentComponent: SideBar
}
);
const switchNavigator = createSwitchNavigator(
{
LoginStack: LoginStack,
HomeStack: DrawerStack
},
{
headerMode: "none",
initialRouteName: "LoginStack"
}
);
const AppContainer = createAppContainer(switchNavigator);
export default AppContainer;
this is the component DetailScreen
import React from "react";
import { StyleSheet } from "react-native";
import { STYLES } from "../../styles/Styles";
import {
Container,
Header,
Title,
Left,
Icon,
Right,
Button,
Body,
Content,
Text,
Card,
CardItem
} from "native-base";
const ContainerDetail = props => {
return (
<Container>
<Header style={STYLES.bgAzulPatios}>
<Left>
<Button transparent onPress={() => props.navigation.goBack()}>
<Icon name="arrow-back" />
</Button>
</Left>
<Body>
<Title>Detail Container</Title>
</Body>
<Right />
</Header>
<Content padder>
<Card>
<CardItem>
<Body>
<Text>Detail Container</Text>
</Body>
</CardItem>
</Card>
</Content>
</Container>
);
};
export default DetailScreen;
this is HomeScreen
import React from "react";
import { StyleSheet, StatusBar } from "react-native";
import { STYLES } from "../../styles/Styles";
import {
Container,
Header,
Title,
Left,
Icon,
Right,
Button,
Body,
Content,
Text,
Card,
CardItem
} from "native-base";
const Home = props => {
closeDrawer = () => {
this.drawer._root.close();
};
openDrawer = () => {
this.drawer._root.open();
};
return (
<Container>
<Header style={STYLES.bgAzulPatios}>
<Left>
<Button transparent onPress={() => props.navigation.openDrawer()}>
<Icon name="menu" />
</Button>
</Left>
<Body>
<Title>HomeScreen</Title>
</Body>
<Right />
</Header>
<Content padder>
<Card>
<CardItem>
<Body>
<Text> Home</Text>
<Button
style={STYLES.bgAzulPatios}
iconLeft
onPress={() => props.navigation.push("ContainerDetail")}
>
<Icon name="arrow-forward" />
<Text>Container Detail</Text>
</Button>
</Body>
</CardItem>
</Card>
</Content>
</Container>
);
};
export default Home;
app.js
.
.
.
render() {
return (
<UserNavigation />
);
}
}
The mistake you are doing here is Login is a different stack and you should not add your detailed screen as a part of Login
Reason: You are making Login as different stack so that when user logs in and even if he presses back button as we came to different stack there is no page behind so the app closes without going to Login Page. So here if you add Detailed Page as a part of login stack it doesnot work
Solution: For Home create another homeStackRoutingComponent with pages like home, detailed and add that as a screen for home
Ex: Home: {
screen: homeStackComponent
}
Here homeStackComponent contains a Stack Container with home, detailed routes with initial route as home :)
In my app, I have Login Screen, ForgotPassword Screen and SignUp Screen. In SignUp Screen I have used react-native-swiper to displays three step's slides of signup process. And I have wrap-up these screens in StackNavigator and render this StackNavigator as a root component in my App.js.
Here is my StackNavigator :
Router.js
import { createDrawerNavigator, createAppContainer, createStackNavigator } from 'react-navigation';
import Login from './src/containers/Login';
import SignUp from './src/containers/SignUp';
import ForgotPassword from './src/containers/ForgotPassword';
const AuthStackNavigator = createStackNavigator({
Login: {
screen: Login
},
ForgotPassword: {
screen: ForgotPassword
},
SignUp: {
screen: SignUp
},
});
const Router = createAppContainer(AuthStackNavigator)
export default Router
App.js
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import configureStore from './src/store/configureStore';
import Router from './Router';
const store = configureStore()
class App extends Component {
render() {
return (
<Provider store={store}>
<Router />
</Provider>
);
}
}
export default App
SignUp.js
import React, { Component } from 'react';
import { View, StyleSheet, TouchableOpacity, KeyboardAvoidingView, Platform, Dimensions } from 'react-native';
import Swiper from 'react-native-swiper';
import Colors from '../../config/Colors';
import Logo from '../components/Logo';
import MText from '../components/MText';
import StepButton from '../components/StepButton';
import SignUpStepOne from './SignUpStepOne';
import SignUpStepTwo from './SignUpStepTwo';
import SignUpStepThree from './SignUpStepThree';
class SignUp extends Component {
static navigationOptions = ({navigation}) => ({
header: null
});
constructor(props) {
super(props);
this.state = {
activeStep: 0
};
}
slideToNext = () => {
this.swiper.scrollBy(1, true);
this.setState(prevState => ({
activeStep: prevState.activeStep + 1
}))
}
slideToPrev = () => {
this.setState(prevState => ({
activeStep: prevState.activeStep - 1
}), () => {
this.swiper.scrollBy(-1, true);
})
}
render() {
<KeyboardAvoidingView style={styles.container} behavior="padding">
<View style={{ flex: 1, paddingHorizontal: 10 }}>
<Logo />
<Swiper
style={{
}}
ref={(swiper) => { this.swiper = swiper; }}
containerStyle={{ flex: 1 }}
showsButtons={false}
showsPagination={false}
loop={false}
scrollEnabled={false}
onIndexChanged={(activeStep) => {
this.setState({
activeStep
})
}}
>
<SignUpStepOne onNext={this.slideToNext} />
<SignUpStepTwo onNext={this.slideToNext} onPrev={this.slideToPrev} />
<SignUpStepThree onNext={this.slideToNext} onPrev={this.slideToPrev} />
</Swiper>
</View>
</KeyboardAvoidingView>
}
}
But, the problem is that when I navigate from Login screen to SignUp screen using this.props.navigation.navigate('SignUp'), Swiper componen not displaying anything in SignUp screen. It just blank. For android it working properly, For IOS it is not working.
And another thing to note is that If I just render SignUp screen as a root in App.js then it is working properly.
And also If I set SignUp screen as a initial screen in my StackNavigator then also it's working.
Please anyone help me what's going wrong here ?
I Have found the solution.
Add removeClippedSubviews={false} props to swiper. Then It will work.
If Swiper isn't working use these props
removeClippedSubviews={false}
scrollEnabled={true}
I just started react-native.
When I try to use the createMaterialBottomTabNavigator from 'react-navigatioin-tabs', I got this warning msg. I have no idea which part makes trouble from the code
maybe it's misuse something..
Could you help me out..?
code below..
import { createMaterialBottomTabNavigator
} from 'react-navigation-tabs';
import Home from '../Screens/HomeScreen/Home'
import Maps from '../Screens/HomeScreen/Maps'
import My from '../Screens/HomeScreen/My'
import Subjects from '../Screens/HomeScreen/Subjects'
const BottomTabNavigation = createMaterialBottomTabNavigator(
{
Home: { screen: Home },
Maps: { screen: Maps },
My: { screen: My },
Subjects: { screen: Subjects },
},
{
initialRouteName: 'Home',
activeTintColor: '#F44336',
}
);
export default BottomTabNavigation
BottomTabNavigation.js
import React, { Component } from 'react';
import {
NativeModules,
Text,
View,
} from 'react-native';
import styles from '../../Styles/HomeScreen/styles';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
class Home extends Component {
static navigationOptions = {
tabBarColor: '#3F51B5',
tabBarIcon: <MaterialIcons
style={{ backgroundColor: 'transparent' }}
name='photo-album'
color='red'
size={24}
/>,
};
render(){
return (
<View style={styles.container}>
<Text>Home</Text>
</View>
);
}
}
export default Home;
Home.js
The problem lies in tabBarIcon, which is defined as a function which returns another function. So you would need to invoke that inner function as well ( tabBarIcon('photo-album')() ). And another thing: where is your tintColor variable extracted from?
I would change your code, and do something like this:
const tabBarIcon = (name, tintColor) => (
<MaterialIcons
style={{ backgroundColor: 'transparent' }}
name={name}
color={tintColor}
size={24}
/>
);
class Home extends React.Component {
static navigationOptions = {
tabBarColor: '#3F51B5',
tabBarIcon: tabBarIcon('photo-album', 'SOME_COLOR'),
title: 'good job!',
};
render() { ... }
}
change import * as React from 'react'; to
import React, { Component } from 'react';
export default class Home extends Component {
}
Hope that help
I need to implement a <BackButton /> in react-admin for example when I open show page for a resource I need able to back to the list page.
Can you guide me to implement this?
I'm not familiar with react-admin routing mechanism.
Now I'm using this component in my edit form actions props:
const MyActions = ({ basePath, data, resource }) => (
<CardActions>
<ShowButton basePath={basePath} record={data} />
<CloneButton basePath={basePath} record={data} />
{/* Need <BackButton /> here */}
</CardActions>
);
export const BookEdit = (props) => (
<Edit actions={<MyActions />} {...props}>
<SimpleForm>
...
</SimpleForm>
</Edit>
);
You can use react-router-redux's goBack() function to achieve this.
For example, your button component will look something like this:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import Button from '#material-ui/core/Button';
import { goBack } from 'react-router-redux';
class BackButton extends Component {
handleClick = () => {
this.props.goBack();
};
render() {
return <Button variant="contained" color="primary" onClick={this.handleClick}>Go Back</Button>;
}
}
export default connect(null, {
goBack,
})(BackButton);
Now use that button component in your CardActions.
You can get help from an example which uses react-router-redux's push() function in a similar way from the official docs.
Create a back button. This one will pass props and children (text) and uses react-router directly, which I think makes more sense and keeps your code simple.
// BackButton.js
import React from 'react'
import Button from '#material-ui/core/Button'
import { withRouter } from 'react-router'
const BackButton = ({ history: { goBack }, children, ...props }) => (
<Button {...props} onClick={goBack}>
{children}
</Button>
)
export default withRouter(BackButton)
Example usage:
import { Toolbar, SaveButton } from 'react-admin'
import BackButton from './BackButton'
const SomeToolbar = props => (
<Toolbar {...props}>
<SaveButton />
<BackButton
variant='outlined'
color='secondary'
style={{ marginLeft: '1rem' }}
>
Cancel
</BackButton>
</Toolbar>
)
The complete code is below.
//BackButton.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import compose from 'recompose/compose';
import { withStyles, createStyles } from '#material-ui/core/styles';
import { translate } from 'ra-core';
import Button from '#material-ui/core/Button';
import ArrowBack from '#material-ui/icons/ArrowBack';
import classnames from 'classnames';
import { fade } from '#material-ui/core/styles/colorManipulator';
const styles = theme =>
createStyles({
deleteButton: {
color: theme.palette.error.main,
'&:hover': {
backgroundColor: fade(theme.palette.error.main, 0.12),
// Reset on mouse devices
'#media (hover: none)': {
backgroundColor: 'transparent',
},
},
},
});
const sanitizeRestProps = ({
basePath,
className,
classes,
label,
invalid,
variant,
translate,
handleSubmit,
handleSubmitWithRedirect,
submitOnEnter,
record,
redirect,
resource,
locale,
...rest
}) => rest;
class BackButton extends Component {
static contextTypes = {
router: () => true, // replace with PropTypes.object if you use them
}
static propTypes = {
label: PropTypes.string,
refreshView: PropTypes.func.isRequired,
icon: PropTypes.element,
};
static defaultProps = {
label: 'ra.action.back',
icon: <ArrowBack />,
};
render() {
const {
className,
classes = {},
invalid,
label = 'ra.action.back',
pristine,
redirect,
saving,
submitOnEnter,
translate,
icon,
onClick,
...rest
} = this.props;
return (
<Button
onClick={this.context.router.history.goBack}
label={label}
className={classnames(
'ra-back-button',
classes.backButton,
className
)}
key="button"
{...sanitizeRestProps(rest)}>
{icon} {label && translate(label, { _: label })}
</Button>
)
}
}
const enhance = compose(
withStyles(styles),
translate
);
export default enhance(BackButton);
//Toolbar.js
import React from 'react';
import {
Toolbar,
SaveButton,
DeleteButton,
} from 'react-admin';
import { withStyles } from '#material-ui/core';
import BackButton from './BackButton'
const toolbarStyles = {
toolbar: {
display: 'flex',
justifyContent: 'space-between',
},
};
export const CustomEditToolbar = withStyles(toolbarStyles)(props => (
<Toolbar {...props}>
<SaveButton/>
<DeleteButton/>
<BackButton/>
</Toolbar>
));
export const CustomCreateToolbar = withStyles(toolbarStyles)(props => (
<Toolbar {...props}>
<SaveButton/>
<BackButton/>
</Toolbar>
));