Navigation in React Router v4 Native Not Changing Scenes - react-native

I'm using React Router for a React Native app. Not sure what I'm missing here but I install react-router-native and require the history package, and setup a couple methods that just push a new route onto the stack but nothing happens. I console.log('clicked'); to check that it's firing and it is so not sure what's wrong.
import React, { Component } from 'react';
import { View } from 'react-native';
import Splash from './Splash';
import createHistory from 'history/createMemoryHistory';
const history = createHistory();
class SplashContainer extends Component {
goToLogin = () => {
history.push('/Login');
}
goToRegister = () => {
history.push('/SignUp');
}
render () {
console.log(history)
return (
<Splash
goToLogin={this.goToLogin}
goToRegister={this.goToRegister}
/>
);
}
}
export default SplashContainer;
import React from 'react';
import { StyleSheet, View, Text } from 'react-native';
import { Button } from 'native-base';
import { Link } from 'react-router-native';
import PropTypes from 'prop-types';
const Splash = (props) => {
console.log(props)
return (
<View style={styles.container}>
<Button light block onPress={props.goToLogin}>
<Text>Login</Text>
</Button>
<Button dark block bordered style={{marginTop: 10}} onPress={props.goToRegister}>
<Text>Register</Text>
</Button>
</View>
);
}
Splash.propTypes = {
goToLogin: PropTypes.func.isRequired,
goToRegister: PropTypes.func.isRequired
}
export default Splash;

I don't know your Router config, but your methods should be:
goToLogin = () => {
const { history } = this.props
history.push('/Login');
}
history will passed down via props of component inside Router's stack.

Related

How to fix an Objects are not valid as a React child Error?

I am very new to programming with React-native, and I was wondering if anyone could explain how I should fix this error? I was following along with a tutorial and had an error come up due to this section of code, even though it matched the tutorial code.
Here is the section of code:
import React, { createContext, useContext } from "react";
import * as Google from "expo-google-app-auth";
const AuthContext = createContext({});
export const AuthProvider = ({ children }) => {
const signInWithGoogle = async() => {
await Google.logInAsync
}
return (
<AuthContext.Provider
value={{
user: null,
}}
>
{children}
</AuthContext.Provider>
);
};
export default function useAuth() {
return useContext(AuthContext);
}
These other two sections may be relevant as well:
Root of the App:
import React from 'react';
import { Text, View, SafeAreaView, Button, Alert } from 'react-native';
import AuthProvider from "./hooks/useAuth";
import StackNavigator from "./StackNavigator";
import { NavigationContainer} from "#react-navigation/native";
// Function for creating button
export default function App() {
return (
<NavigationContainer>
<AuthProvider>
<StackNavigator />
</AuthProvider>
</NavigationContainer>
);
}
This is my code for the Login Screen:
import React from 'react';
import { View, Text } from 'react-native';
import useAuth from '../hooks/useAuth';
const LoginScreen = () => {
const { user } = useAuth();
console.log(user);
return (
<View>
<Text>
Login to the app
</Text>
</View>
);
};
export default LoginScreen
This is the error that appears:
Error: Objects are not valid as a React child (found: object with keys {}). If you meant to render a collection of children, use an array instead.
I suggest you auth with firebase. it makes easier this things.

Implement BackButton in React-Admin v4

Before version 4, we could create BackButton like this:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import Button from '#material-ui/core/Button';
import ArrowBack from '#material-ui/icons/ArrowBack';
import { goBack } from 'react-router-redux';
class BackButton extends Component {
handleClick = () => {
this.props.goBack();
};
render() {
return <Button startIcon={<ArrowBack />} color="primary" onClick={this.handleClick}>Назад</Button>;
}
}
export default connect(null, {
goBack,
})(BackButton);
How do we create BackButton in react-admin version 4 ?
That library was deprecated a long time ago.
The natural upgrade of react-router-redux is connected-react-router.
In react-admin upgrade guide for version 4 is explained how to move away from connected-react-router:
Basically, now you have to use useNavigate hook from react-router:
https://marmelab.com/react-admin/Upgrade.html#removed-connected-react-router
Plus in your case you will have to change your component to a function component first.
Something like this:
import React, { Component } from 'react';
import Button from '#mui/material/Button';
import ArrowBack from '#mui/icons-material/ArrowBack';
import { useNavigate } from 'react-router';
const BackButton = props => {
const navigate = useNavigate();
handleClick = () => {
navigate(-1);
};
return (
<Button
startIcon={<ArrowBack />}
color="primary"
onClick={handleClick}
>
Назад
</Button>
);
}

Unable to load provider from react-redux module in react native

I am creating a slide bar, In that, I have used the react-redux library. When I call the class which contains the redux-code, it works fine. I want to show this slide bar after login. Therefore, with conditions (I set a state variable if user login successfully then only this page should get rendered), I tried to call the same file which shows a blank page. I printed the console log. I am able to print all the logs. But with conditions, I am not able to load the data.
I don't know much about react-redux.Can you assist me to resolve this?
My code is,
main.js,
import React, {Component} from 'react';
import {
StyleSheet,
Dimensions,
Platform,
View,
StatusBar,
DrawerLayoutAndroid,
} from 'react-native';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import reducer from '../Redux/reducers';
import { setNavigator, setActiveRoute } from "../Redux/actions";
import DrawerContent from '../Navigation/DrawerContent';
import Toolbar from '../Navigation/Toolbar';
import AppNavigation from '../Navigation/AppNavigation';
import { bgStatusBar, bgDrawer } from '../global.styles';
let store = createStore(reducer);
/* getDrawerWidth Default drawer width is screen width - header width
* https://material.io/guidelines/patterns/navigation-drawer.html
*/
const getDrawerWidth = () => Dimensions.get('window').width - (Platform.OS === 'android' ? 56 : 64);
export default class Main extends Component {
constructor() {
super();
this.drawer = React.createRef();
this.navigator = React.createRef();
}
componentDidMount() {
store.dispatch(setNavigator(this.navigator.current));
}
openDrawer = () => {
this.drawer.current.openDrawer();
};
closeDrawer = () => {
this.drawer.current.closeDrawer();
};
getActiveRouteName = navigationState => {
if (!navigationState) {
return null;
}
const route = navigationState.routes[navigationState.index];
// dive into nested navigators
if (route.routes) {
return getActiveRouteName(route);
}
return route.routeName;
};
render() {
return (
<Provider store={store}>
<DrawerLayoutAndroid
drawerWidth={getDrawerWidth()}
drawerPosition={DrawerLayoutAndroid.positions.Left}
renderNavigationView={
() => <DrawerContent closeDrawer={this.closeDrawer} />
}
ref={this.drawer}
>
<View style={styles.container}>
<StatusBar
translucent
animated
/>
<Toolbar showMenu={this.openDrawer} />
<AppNavigation
onNavigationStateChange={(prevState, currentState) => {
const currentScreen = this.getActiveRouteName(currentState);
store.dispatch(setActiveRoute(currentScreen));
}}
ref={this.navigator}
/>
</View>
</DrawerLayoutAndroid>
</Provider>
);
}
}
Login.js
import Main from './main';
render() {
return (
<View>
{this.state.isLoggedIn ?
<Main/>
:
<ChangePassword isUpdatePassword={this.state.isUpdatePassword} callLogin={this.callLogin}/>
);
}
}
If I just call Main class inside render method it works. But It does not work with conditions.

Error: Check the render method with react-redux connect()

I'm trying to learn redux with react-native, so I did some examples, but for everyone, even though they are different, I'm getting the same error.
My code is like this:
index.js:
import { AppRegistry } from 'react-native';
import App from './src/app';
AppRegistry.registerComponent('reduxExample', () => App);
src/app.js:
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { Store } from './store';
import Home from './components/home';
export default props => (
<Provider store={Store}>
<Home />
</Provider>
)
src/components/home.js:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { View, Text, Button, Input } from 'react-native';
class Home extends Component {
render() {
const { newValue } = this.props;
return (
<View>
<Input type='text' />
<Button>
Click me!
</Button>
<Text>{newValue}</Text>
</View>
);
}
}
const mapStateToProps = store => ({
newValue: store.clickState.newValue
});
export default connect(mapStateToProps)(Home)
src/store/index.js:
import { createStore } from 'redux';
import { Reducers } from '../reducers';
export const Store = createStore(Reducers);
The rest I believe they do not have to deal with the problem but if I need to put the code.
There is no <Input type='text' /> tag in react native. There is only a <TextInput /> tag.

Passing in action creators to react-navigation

I'm using the new react-navigation library for a React Native application I'm building. I'm having an issue with passing down my ActionCreators from my Nav component down to its scenes.
I have an AppContainer that wraps the entire application.
import React, { Component } from 'react';
import { DrawerNavigator, addNavigationHelpers } from 'react-navigation';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { ActionCreators } from '../actions';
import DashboardContainer from './DashboardContainer';
import CustomersContainer from './CustomersContainer';
const ApplicationNavigation = DrawerNavigator({
Dashboard: { screen: DashboardContainer },
Customers: { screen: CustomersContainer },
});
class AppContainer extends Component {
render() {
return (
<ApplicationNavigation />
);
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(ActionCreators, dispatch);
}
export default connect(() => { return {} }, mapDispatchToProps)(AppContainer);
Here is the CustomerContainer:
import React, {Component} from 'react';
import {View, Text, Button} from 'react-native';
export default class CustomerContainer extends Component {
btnPressed() {
this.props.listCustomers()
}
render () {
return (
<View style={{marginTop: 40}}><Text>Customer</Text>
<Button onPress={() => this.btnPressed()} title="Press Me!" />
</View>
);
}
}
Now I'm trying to call an action within my CustomerContainer this.props.listCustomers(). The problem is the ActionCreator props aren't being passed down to the screens. I've tried doing adding the screenProps prop to the ApplicationNavigation component:
But for some reason when I do this my app doesn't display any screens its just blank with no errors.
UPDATE
So I updated my CustomerContainer file:
import React, {Component} from 'react';
import {View, Text, Button} from 'react-native';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { ActionCreators } from '../actions';
class CustomerContainer extends Component {
btnPressed() {
console.log(this.props.listCompanyCustomers())
}
render () {
return (
<View style={{marginTop: 40}}><Text>Customer</Text>
<Button onPress={() => this.btnPressed()} title="Press Me!" />
</View>
);
}
}
function mapStateToProps(state) {
return {
companyCustomers: state.companyCustomers
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(ActionCreators, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(CustomerContainer);
This now works; however this feels like the incorrect way to go about this.
What redux connect basically does is:
Wrap your component
Declare contextProps to get access to dispatch
pass the dispatch to your component props.
If you pass the connect mapDispatchToProps, then it creates the mapping of the methods to dispatch.
So if you connect you AppContainer, its children won't get these dispatch methods, unless AppContainer passes them to its children (but this what connect comes to prevent).
So to sum up, you should connect any component that needs to use dispatch, otherwise it won't get it.
If you don't want to copy paste the mapDispatchToProps, you can just delete it and use this.props.dispatch instead:
import { ActionCreators } from '../actions';
class CustomerContainer extends Component {
btnPressed() {
this.props.dispatch(ActionCreators.listCompanyCustomers());
}
render () {
return (
<View style={{marginTop: 40}}><Text>Customer</Text>
<Button onPress={() => this.btnPressed()} title="Press Me!" />
</View>
);
}
}