please take a look at this code my signup button doesn't direct me to profile component react native - react-native

Help me with this so I can carry further on with my work.
Also all the other files which are needed for the solution I can provide you with.
profile.js
import React from "react";
import { StyleSheet, Text, View, StatusBar } from "react-native";
import { render } from "react-dom";
class Profile extends React.Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.textStyle}>This is the profile page </Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: "#455a64",
flex: 1,
alignItems: "center",
justifyContent: "center",
},
textStyle: {
color: "#fff",
fontSize: 18,
},
});
export default Profile;
signup.js
import React from "react";
import {
StyleSheet,
Text,
View,
StatusBar,
TouchableOpacity,
} from "react-native";
import { createNewUser } from "/Users/ayeshasiddiquebutt/elearning9thclassapp/sourcefiles/actions/auth.actions.js";
import { render } from "react-dom";
import { connect } from "react-redux";
import Form from "/Users/ayeshasiddiquebutt/elearning9thclassapp/sourcefiles/components/form.js";
import { compose } from "redux";
import Logo from "/Users/ayeshasiddiquebutt/elearning9thclassapp/sourcefiles/components/logo.js";
import SignupForm from "/Users/ayeshasiddiquebutt/elearning9thclassapp/sourcefiles/components/signupform.js";
import { Actions } from "react-native-router-flux";
import { Field, reduxForm } from "redux-form";
import InputText from "/Users/ayeshasiddiquebutt/elearning9thclassapp/sourcefiles/components/InputText.js";
import Loader from "/Users/ayeshasiddiquebutt/elearning9thclassapp/sourcefiles/components/Loader.js";
class Signup extends React.Component {
goBack() {
Actions.pop();
}
createNewUser = (values) => {
this.props.dispatch(createNewUser(values));
};
onSubmit = (values) => {
this.createNewUser(values);
};
renderTextInput = (field) => {
const {
meta: { touched, error },
label,
secureTextEntry,
maxLength,
keyboardType,
placeholder,
input: { onChange, ...restInput },
} = field;
return (
<View>
<InputText
onChangeText={onChange}
maxLength={maxLength}
placeholder={placeholder}
keyboardType={keyboardType}
secureTextEntry={secureTextEntry}
label={label}
{...restInput}
/>
{touched && error && <Text style={styles.errorText}>{error}</Text>}
</View>
);
};
render() {
const { createUsers, handleSubmit } = this.props;
return (
<View style={styles.container}>
{createUsers.isLoading && <Loader />}
<Logo />
<Field
name="name"
placeholder=" First Name"
component={this.renderTextInput}
/>
<Field
name="name"
placeholder=" Last Name"
component={this.renderTextInput}
/>
<Field
name="email"
placeholder="Email"
component={this.renderTextInput}
/>
<Field
name="password"
placeholder="Password"
secureTextEntry={true}
component={this.renderTextInput}
/>
<TouchableOpacity
style={styles.button}
onPress={handleSubmit(this.onSubmit)}
>
<Text style={styles.buttonText}>Signup</Text>
</TouchableOpacity>
<View style={styles.signupTextCont}>
<Text style={styles.signupText}>Already have an account?</Text>
<TouchableOpacity onPress={this.goBack}>
<Text style={styles.signupButton}> Sign in</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
const validate = (values) => {
const errors = {};
if (!values.name) {
errors.name = "First Name is required";
}
if (!values.name) {
errors.name = "Last Name is required";
}
if (!values.email) {
errors.email = "Email is required";
}
if (!values.password) {
errors.password = "Password is required";
}
return errors;
};
const styles = StyleSheet.create({
container: {
backgroundColor: "#455a64",
flex: 1,
alignItems: "center",
justifyContent: "center",
},
signupTextCont: {
flexGrow: 1,
alignItems: "flex-end",
justifyContent: "center",
paddingVertical: 16,
flexDirection: "row",
},
signupText: {
color: "rgba(255,255,255,0.6)",
fontSize: 16,
},
signupButton: {
color: "#ffffff",
fontSize: 16,
fontWeight: "500",
},
button: {
width: 300,
backgroundColor: "#1c313a",
borderRadius: 25,
marginVertical: 10,
paddingVertical: 13,
},
buttonText: {
fontSize: 16,
fontWeight: "500",
color: "#ffffff",
textAlign: "center",
},
errorText: {
color: "#ffffff",
fontSize: 14,
paddingHorizontal: 16,
paddingBottom: 8,
},
inputBox: {
width: 300,
backgroundColor: "rgba(255, 255,255,0.2)",
borderRadius: 25,
paddingHorizontal: 16,
fontSize: 16,
color: "#ffffff",
marginVertical: 10,
},
});
mapStateToProps = (state) => ({
createUsers: state.authReducer.createUsers,
});
mapDispatchToProps = (dispatch) => ({
dispatch,
});
export default compose(
connect(mapStateToProps, mapDispatchToProps),
reduxForm({
form: "register",
validate,
})
)(Signup);
auth.reducer.js
import { combineReducers } from "redux";
const createUsers = (state = {}, action) => {
switch (action.type) {
case "CREATE_USER_LOADING":
return {
isLoading: true,
isError: false,
isSuccess: false,
errors: null,
isLoggedIn: false,
};
case "CREAT_USER_SUCCESS":
return {
isLoading: false,
isError: false,
isSuccess: true,
errors: null,
isLoggedIn: true,
};
case "CREAT_USER_FAIL":
return {
isLoading: false,
isError: true,
isSuccess: false,
errors: action.payload,
isLoggedIn: false,
};
default:
return state;
}
};
/*const authData = (state = {}, action) => {
switch (action.type) {
case "AUTH_USER_SUCCESS":
return {
token: action.token,
isLoggedIn: true,
};
case "AUTH_USER_FAIL":
return {
token: null,
isLoggedIn: false,
};
default:
return state;
}
};
const loginUser = (state = {}, action) => {
switch (action.type) {
case "LOGIN_USER_LOADING":
return {
isLoading: true,
isError: false,
isSuccess: false,
errors: null,
};
case "LOGIN_USER_SUCCESS":
return {
isLoading: false,
isError: false,
isSuccess: true,
errors: null,
};
case "LOGIN_USER_FAIL":
return {
isLoading: false,
isError: true,
isSuccess: false,
errors: action.payload,
};
default:
return state;
}
};*/
export default combineReducers({
createUsers,
//loginUser,
//authData,
});
routes.js
import React, { Component } from "react";
import {
StyleSheet,
Text,
View,
StatusBar,
TouchableOpacity,
} from "react-native";
import { Router, Stack, Scene } from "react-native-router-flux";
import Login from "../pages/login.js";
import Signup from "/Users/ayeshasiddiquebutt/elearning9thclassapp/sourcefiles/pages/signup.js";
import Profile from "../pages/profile.js";
class Routes extends React.Component {
render() {
return (
<Router>
<Scene>
<Scene key="root" hideNavBar={true} initial={!this.props.isLoggedIn}>
<Scene key="signup" component={Signup} title="Register" />
<Scene key="login" component={Login} />
</Scene>
<Scene key="app" hideNavBar={true} initial={this.props.isLoggedIn}>
<Scene key="profile" component={Profile} initial={true} />
</Scene>
</Scene>
</Router>
);
}
}
export default Routes;
Main.js
import React from "react";
import {
StyleSheet,
Text,
View,
StatusBar,
TouchableOpacity,
} from "react-native";
import { render } from "react-dom";
import { createUsers } from "/Users/ayeshasiddiquebutt/elearning9thclassapp/sourcefiles/reducers/auth.reducer.js";
import { connect } from "react-redux";
import Routes from "/Users/ayeshasiddiquebutt/elearning9thclassapp/sourcefiles/components/routes.js";
import { Actions } from "react-native-router-flux";
class Main extends React.Component {
render() {
const { createUsers } = this.props;
console.log(this.props.createUsers.isLoggedIn);
return (
<View style={styles.container}>
<StatusBar backgroundColor="#1c313a" barStyle="light-content" />
<Routes isLoggedIn={this.props.createUsers.isLoggedIn} />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
mapStateToProps = (state) => ({
createUsers: state.authReducer.createUsers,
});`enter code here`
export default connect(mapStateToProps, null)(Main);

Related

Check the render method of 'customComponent'

I have made a Login page in React Native with React hooks along with redux thunk connect.
In that Login Page, i have import a LoginForm as customComponent and I have properly export and import that component.But still it produce Element type error.
LoginPage
import React, { useState } from "react";
import {
View,
Text,
TouchableOpacity,
StyleSheet,
Dimensions,
} from "react-native";
import PropsType from "prop-types";
import { connect } from "react-redux";
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scrollview";
import SimpleReactValidator from "simple-react-validator";
import Img from "../../common/Img";
import Loader from "../../common/Loader";
import styles from "../../globalStyle";
import * as theme from "../../theme";
import AxiosInstance from "../../helper/axios.interceptor";
import * as globalHelper from "../../helper/globalHelper";
import { setAuth } from "../../store/auth/auth.action";
import LoginForm from "./Component/LoginForm";
const { height } = Dimensions.get("screen");
const propsType = {
authAction: PropsType.func,
};
let request = { type: "mobile" };
const validator = new SimpleReactValidator();
const SignIn = ({ navigation, authAction }) => {
const [errors, setErrors] = useState({});
const [state, setState] = useState({ loader: false }),
updateState = (key, value) => {
setState((preState) => ({
...preState,
[key]: value,
}));
},
openLoader = (val) => {
updateState("loader", val);
};
const submit = async () => {
try {
openLoader(true);
let body = {
type: "mobile",
userName: request.userName,
password: request.password,
};
console.log("body", body);
const response = await AxiosInstance.post("auth/login", body);
console.log("loginresponse...", response);
if (response.status) {
await globalHelper.setAsyncStore("user", response);
await globalHelper.setAsyncStore(
"userpermission",
response.data.permissionJson
);
authAction(response);
navigation.replace("AppNavigation");
}
openLoader(false);
} catch (err) {
openLoader(false);
console.log("login error", err);
}
};
//
const ForgotPassword = () => (
<TouchableOpacity
onPress={() => {
validator.hideMessages();
setErrors("");
navigation.push("ForgotPassword");
}}
>
<Text style={[localStyle.forgotText]}>Forgot Password?</Text>
</TouchableOpacity>
);
return (
<>
<KeyboardAwareScrollView>
<View style={[styles.flexCenter, { height }]}>
<Img
src={require("../../assets/logo/logoNew.png")}
style={{ width: 237, height: 250, marginBottom: -20 }}
resizeMode="contain"
/>
<View style={localStyle.authButton}>
<LoginForm
validator={validator}
onTextChanging={(data) => {
request = { ...request, ...data };
}}
onSubmit={() => {
submit();
}}
errors={errors}
setErrors={setErrors}
/>
</View>
<View style={[styles.flexCenter]}>
<ForgotPassword />
</View>
</View>
</KeyboardAwareScrollView>
{state.loader && <Loader />}
</>
);
};
const { color } = theme;
const localStyle = StyleSheet.create({
authButton: {
width: "80%",
borderRadius: 5,
},
forgotText: {
marginTop: 20,
color: color.hashTextColor,
},
});
SignIn.propsType = propsType;
const mapDispatchToProps = {
authAction: setAuth,
};
export default connect(null, mapDispatchToProps)(SignIn);
and the customComponent LoginForm as
import React, { useState, useEffect, useRef } from "react";
import {
View,
Text,
TouchableOpacity,
ScrollView,
StyleSheet,
} from "react-native";
import { Form, Icon } from "native-base";
import PropsType from "prop-types";
import { has } from "lodash";
import RegularInput from "../../../common/Input";
import styles from "../../../globalStyle";
import AuthButton from "../../../common/Button/AuthButton";
const propsType = {
onTextChanging: PropsType.func.isRequired,
onSubmit: PropsType.func.isRequired,
};
// const validator = new SimpleReactValidator();
const LoginForm = ({
onTextChanging,
onSubmit,
validator,
errors,
setErrors,
}) => {
const [model, setModel] = useState({ focus: "username", secured: true });
const isValid = (key) => !!(has(errors, key) && errors[key]);
const [state, setState] = useState({
userName: "",
password: "",
});
const secondTextInput = useRef(null);
useEffect(() => {
onTextChanging(state);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [state]);
const updateState = (key, value) => {
setState((preState) => ({
...preState,
[key]: value,
}));
};
const submit = () => {
if (validator.allValid()) {
onSubmit();
} else {
console.log("getErrorMessages");
setErrors(validator.getErrorMessages());
validator.showMessages();
}
};
return (
<ScrollView keyboardShouldPersistTaps="handled">
<Form style={[styles.top50, { width: "100%" }]}>
<View style={{ width: "100%", paddingBottom: 15 }}>
<RegularInput
title="Email"
value={state.userName}
attri="userName"
placeHolder={"Email"}
keyboardType="ascii-capable"
updateStateFunc={updateState}
error={isValid("Username")}
isFocus={model.focus === "username"}
onFocusFun={() => setModel({ focus: "username" })}
otherProps={{
onSubmitEditing: () => {
console.log(secondTextInput);
secondTextInput.current.focus();
},
blurOnSubmit: false,
}}
/>
</View>
{!!validator.message("Email", state.userName, "email") && (
<Text style={[styles.error]}>
{validator.message("Email", state.userName, "email")}
</Text>
)}
<View
style={[
styles.flexCenter,
styles.flexRow,
localStyle.absoluteContainer,
]}
>
<RegularInput
reff={secondTextInput}
title="Password"
value={state.password}
attri="password"
placeHolder={"Password"}
updateStateFunc={updateState}
dataDetectorTypes="phoneNumber"
secureTextEntry={!state.secured}
error={isValid("Password")}
isFocus={model.focus === "password"}
onFocusFun={() => setModel({ focus: "password" })}
/>
<TouchableOpacity
style={localStyle.eyeIcon}
onPress={() => {
updateState("secured", !state.secured);
}}
>
{state.secured && (
<Icon style={{ fontSize: 16 }} name="eye" type="Entypo" />
)}
{!state.secured && (
<Icon
style={{ fontSize: 16 }}
name="eye-with-line"
type="Entypo"
/>
)}
</TouchableOpacity>
</View>
{!!validator.message("Password", state.password, "required") && (
<Text style={[styles.error]}>
{validator.message("Password", state.password, "required")}
</Text>
)}
<View style={[styles.flexCenter, localStyle.authButton]}>
<AuthButton title="LOGIN" onPress={() => submit()} />
</View>
</Form>
</ScrollView>
);
};
const localStyle = StyleSheet.create({
authButton: {
marginTop: 10,
borderRadius: 5,
},
inputStyle: {
height: 40,
borderColor: "gray",
borderBottomWidth: 1,
},
absoluteContainer: {
position: "relative",
overflow: "hidden",
width: "100%",
},
eyeIcon: {
position: "absolute",
// right: 0,
width: 25,
height: 25,
elevation: 999,
zIndex: 999,
top: 42,
right: 5,
},
});
LoginForm.propsType = propsType;
export default LoginForm;
I have tried
import LoginForm from "./Component/LoginForm";
as
import {LoginForm} from "./Component/LoginForm";
It produce check the render method of SignIn
and also use connect in LoginForm,
export default connect(null, null)(LoginForm);
but it gives same error. I don't know what mistake i have made.unable to find any cause. Thanks in advance
Element type Error

Could not navigate to another screen when using token in React Native

I'm currently developing an app using react native, right now my issue is that i couldn't navigate to main screen after login. Below is my code.
This is App.js (EDITED)
import React from 'react';
import { Loading } from './components/common/';
import TabNavigator from './screens/TabNavigator';
import AuthNavigator from './screens/AuthNavigator';
import MainNavigator from './screens/MainNavigator';
import deviceStorage from './services/deviceStorage.js';
import { View, StyleSheet } from 'react-native';
export default class App extends React.Component {
constructor() {
super();
this.state = {
token: '',
loading: true
}
this.newJWT = this.newJWT.bind(this);
this.deleteJWT = deviceStorage.deleteJWT.bind(this);
this.loadJWT = deviceStorage.loadJWT.bind(this);
this.loadJWT();
}
state = {
isLoadingComplete: false,
};
newJWT(token){
this.setState({
token: token
});
}
render() {
if (this.state.loading) {
return (
<Loading size={'large'} />
);
} else if (!this.state.token) {
return (
<View style={styles.container}>
<AuthNavigator screenProps = {{setToken:this.newJWT}} />
</View>
);
} else if (this.state.token) {
return (
<View style={styles.container}>
<MainNavigator screenProps = {{token: this.state.token,
deleteJWT:this.deleteJWT,}} />
</View>
);
}
}
}
This is Login.js (EDITED-v2)
import React, { Component, Fragment } from 'react';
import { Text, View, StyleSheet, ImageBackground, KeyboardAvoidingView,
TouchableOpacity, TextInput, Alert } from 'react-native';
import axios from 'axios';
import deviceStorage from '../services/deviceStorage';
class Login extends Component {
constructor(props) {
super(props)
this.state = {
username: '',
password: '',
error: '',
loading: false
};
this.loginUser = this.loginUser.bind(this);
this.onLoginFail = this.onLoginFail.bind(this);
}
loginUser() {
const { username, password, password_confirmation } = this.state;
this.setState({ error: '', loading: true });
// NOTE Post to HTTPS only in production
axios.post("http://192.168.1.201:8000/api/login",{
username: username,
password: password
})
.then((response) => {
console.log('response',response)
deviceStorage.saveKey("token", response.data.token);
console.log(response.data.token);
this.props.newJWT(response.data.token);
})
.catch((error) => {
const status = error.response.status
if (status === 401) {
this.setState({ error: 'username or password not recognised.' });
}
this.onLoginFail();
//console.log(error);
//this.onLoginFail();
});
}
onLoginFail() {
this.setState({
error: 'Login Failed',
loading: false
});
}
render() {
// other codes here
}
const styles = StyleSheet.create({
// other codes here
});
export { Login };
This is TabNavigator.js (Added)
import React from 'react';
import { Text } from 'react-native';
import { createMaterialTopTabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import Profile from '../screens/Profile';
const TabNavigator = createMaterialTopTabNavigator(
{
Profile: {
screen: props => <Profile {...props.screenProps} />,
navigationOptions: {
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-person' : 'ios-person'} //TODO change to focused
icon
size={30}
style={{ color: tintColor }}
/>
),
}
},
},
{ initialRouteName: 'Profile',
tabBarPosition: 'top',
swipeEnabled: false,
animationEnabled: true,
lazy: true,
tabBarOptions: {
showLabel: false,
showIcon: true,
activeTintColor: 'orange',
inactiveTintColor: 'orange',
style: {
backgroundColor: '#555',
},
indicatorStyle: {
color: '#orange'
}
}
}
);
const screenTitles = {
Profile: { title: 'Profiler' },
Home: { title: 'Home' },
};
TabNavigator.navigationOptions = ({ navigation }) => {
const { routeName } = navigation.state.routes[navigation.state.index];
const headerTitle = screenTitles[routeName].title;
const tabBarVisible = false;
return {
headerTitle,
tabBarVisible
};
};
export default TabNavigator;
This is my AuthLoadingScreen.js
import React from 'react';
import { View } from 'react-native';
import { Login } from '../screens/Login';
class AuthLoadingScreen extends React.Component {
constructor(props){
super(props);
this.state = {
showLogin: true
};
this.whichForm = this.whichForm.bind(this);
this.authSwitch = this.authSwitch.bind(this);
}
authSwitch() {
this.setState({
showLogin: !this.state.showLogin
});
}
whichForm() {
if(this.state.showLogin){
return(
<Login newJWT={this.props.newJWT} authSwitch={this.authSwitch} />
);
} else {
}
}
render() {
return(
<View style={styles.container}>
{this.whichForm()}
</View>
);
}
}
export default AuthLoadingScreen;
const styles = {
// style codes here
};
Lastly, this is my Profile.js
import React, { Component } from 'react';
import { View, Text, TouchableOpacity, Alert, Platform } from
'react-native';
import { Button, Loading } from '../components/common/';
import axios from 'axios';
export default class Profile extends Component {
constructor(props){
super(props);
this.state = {
loading: true,
email: '',
name: '',
error: ''
}
}
componentDidMount(){
this.onLocationPressed();
const headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + this.props.token
};
axios({
method: 'GET',
url: 'http://192.168.1.201:8000/api/user',
headers: headers,
}).then((response) => {
console.log('response',response)
console.log('response2',this.props.token)
this.setState({
email: response.data.user.email,
name: response.data.user.name,
loading: false
});
}).catch((error) => {
console.log(error);
this.setState({
error: 'Error retrieving data',
loading: false
});
});
}
render() {
const { container, emailText, errorText } = styles;
const { loading, email, name, error } = this.state;
if (loading){
return(
<View style={container}>
<Loading size={'large'} />
</View>
)
} else {
return(
<View style={container}>
<View>
<Text style={emailText}>Your email: {email}</Text>
<Text style={emailText}>Your name: {name}</Text>
</View>
<Button onPress={this.props.deleteJWT}>
Log Out
</Button>
</View>
);
}
}
}
const styles = {
// style codes here
};
I've fixed the previous problem that couldn't start the app. Right now i can see the login screen, but when i pressed login, there's a yellow box that indicates some problem. I've included the screenshot below.
Lastly i've added the deviceStorage.js
deviceStorage.js
import { AsyncStorage } from 'react-native';
const deviceStorage = {
async saveKey(key, valueToSave) {
try {
await AsyncStorage.setItem(key, valueToSave);
} catch (error) {
console.log('AsyncStorage Error: ' + error.message);
}
},
async loadJWT() {
try {
const value = await AsyncStorage.getItem('token');
if (value !== null) {
this.setState({
token: value,
loading: false
});
} else {
this.setState({
loading: false
});
}
} catch (error) {
console.log('AsyncStorage Error: ' + error.message);
}
},
async deleteJWT() {
try{
await AsyncStorage.removeItem('token')
.then(
() => {
this.setState({
token: ''
})
}
);
} catch (error) {
console.log('AsyncStorage Error: ' + error.message);
}
}
};
export default deviceStorage;
Before navigate
After navigate
This is my setup. It works like a charm. Sorry if it's a bit messy. I removed some stuff for clarity and I may have missed something:
App.js
import React from 'react';
import { Platform, StatusBar, StyleSheet, View } from 'react-native';
import { Asset, Font, Icon } from 'expo';
import { ENDPOINT, USER_TYPE } from './src/config'
import { Loading } from './src/components/common/';
import deviceStorage from './src/services/deviceStorage.js';
import TabNavigator from './src/TabNavigator';
import AuthNavigator from './src/AuthNavigator';
import MainNavigator from './src/MainNavigator';
import globalStyles from './src/globalStyles';
import './ReactotronConfig';
export default class App extends React.Component {
constructor() {
super();
this.state = {
jwt: '',
loading: true,
};
this.newJWT = this.newJWT.bind(this);
this.deleteJWT = deviceStorage.deleteJWT.bind(this);
this.loadJWT = deviceStorage.loadJWT.bind(this);
this.loadJWT();
}
state = {
isLoadingComplete: false,
};
newJWT(jwt) {
this.setState({
jwt: jwt
});
}
render() {
if (this.state.loading) {
return (
<Loading size={'large'} />
);
} else if (!this.state.jwt) {
//console.log(this.props, '<=== app.js');
return (
<View style={styles.container}>
{Platform.OS === 'ios' && <StatusBar barStyle="default" />}
<AuthNavigator screenProps={{setToken: this.newJWT }} />
</View>
);
} else {
return (
<View style={styles.container}>
{Platform.OS === 'ios' && <StatusBar barStyle="default" />}
<MainNavigator
screenProps={{ jwt: this.state.jwt,
deleteToken: this.deleteJWT,
}}
/>
</View>
);
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
justifyContent: 'center',
},
});
AuthNavigator.js
import React from 'react';
import { createAppContainer, createBottomTabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import AuthScreen from './screens/AuthScreen';
const AuthNavigator = createBottomTabNavigator(
{
Auth: (props) => {
return <AuthScreen {...props.screenProps} />;
}
},
{ initialRouteName: 'Auth',
tabBarOptions: {
showLabel: false,
activeBackgroundColor: '#eee',
}
}
);
export default createAppContainer(AuthNavigator);
MainNavigator.js
import React from 'react';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import TabNavigator from './TabNavigator';
const MainNavigator = createStackNavigator({
Main: TabNavigator },
{
initialRouteName: 'Main',
defaultNavigationOptions: {
headerTitleStyle: {
fontSize: 20,
textTransform: 'uppercase'
}
}
});
export default createAppContainer(MainNavigator);
TabNavigator.js
import React from 'react';
import { Text } from 'react-native';
import { createMaterialTopTabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import IconBadge from 'react-native-icon-badge';
import ProfileScreen from './screens/ProfileScreen';
import NotificationsScreen from './screens/NotificationsScreen';
import HomeStackNavigator from './HomeStackNavigator';
import CartStackNavigator from './CartStackNavigator';
import QuotesStackNavigator from './QuotesStackNavigator';
import InitialRoute from './InitialRoute';
const TabNavigator = createMaterialTopTabNavigator(
{
Profile: {
screen: props => <ProfileScreen {...props.screenProps} />,
navigationOptions: {
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-person' : 'ios-person'} //TODO change to focused icon
size={30}
style={{ color: tintColor }}
/>
),
}
},
Home: HomeStackNavigator,
Quotes: QuotesStackNavigator,
Notifications: { screen: props => <NotificationsScreen {...props.screenProps} />,
navigationOptions: ({ screenProps }) => ({
tabBarIcon: ({ tintColor, focused }) => (
<IconBadge
MainElement={
<Ionicons
name={focused ? 'ios-notifications' : 'ios-notifications'}
size={30}
style={{ color: tintColor }}
/>
}
BadgeElement={
<Text style={{ color: '#FFFFFF' }}>{screenProps.unreadMessagesCount}</Text>
}
IconBadgeStyle={{ width: 15,
height: 15,
position: 'absolute',
top: 1,
left: -6,
marginLeft: 15,
backgroundColor: 'red' }}
Hidden={screenProps.unreadMessagesCount === 0}
/>
)
})
},
Cart: CartStackNavigator,
},
{ initialRouteName: 'Profile',
tabBarPosition: 'top',
swipeEnabled: false,
animationEnabled: true,
lazy: true,
tabBarOptions: {
showLabel: false,
showIcon: true,
activeTintColor: 'orange',
inactiveTintColor: 'orange',
style: {
backgroundColor: '#555',
},
indicatorStyle: {
color: '#orange'
}
}
}
);
const screenTitles = {
Profile: { title: 'Hola Maestro' },
Home: { title: 'Selecciona la Categoría' },
Quotes: { title: 'Mi Historial de Cotizaciones' },
Notifications: { title: 'Notificaciones' },
Cart: { title: 'Mi Pedido' },
};
TabNavigator.navigationOptions = ({ navigation }) => {
const { routeName } = navigation.state.routes[navigation.state.index];
const headerTitle = screenTitles[routeName].title;
const tabBarVisible = false;
return {
headerTitle,
tabBarVisible
};
};
export default TabNavigator;
Login.js
import React, { Component, Fragment } from 'react';
import { Text, View, StyleSheet, ImageBackground, KeyboardAvoidingView } from 'react-native';
import axios from 'axios';
import Ionicons from 'react-native-vector-icons/Ionicons';
//import Pusher from 'pusher-js/react-native';
import { ENDPOINT, USER_TYPE } from '../config'
import deviceStorage from '../services/deviceStorage';
import { Input, TextLink, Loading, Button } from './common';
import Header from '../components/Header';
class Login extends Component {
constructor(props){
super(props);
this.state = {
username: '',
password: '',
error: '',
loading: false
};
this.pusher = null; // variable for storing the Pusher reference
this.my_channel = null; // variable for storing the channel assigned to this user
this.loginUser = this.loginUser.bind(this);
}
loginUser() {
const { username, password, password_confirmation } = this.state;
axios.post(`${ENDPOINT}/login`, {
user: {
login: username,
password: password
}
})
.then((response) => {
deviceStorage.saveKey("id_token", response.headers.authorization);
this.props.newJWT(response.headers.authorization);
//this.setPusherData();
})
.catch((error) => {
this.onLoginFail();
});
}
onLoginFail() {
this.setState({
error: 'Usuario o contraseña incorrecta',
loading: false
});
}
}
render() {
const { username, password, error, loading } = this.state;
const { container, form, section, errorTextStyle, iconContainer, inputContainer, titleText } = styles;
return (
<View style={container}>
<Header title="¡Bienvenido Amigo Maestro!" />
<View style={form}>
<ImageBackground source={require('./cemento-login.jpg')} style={{ flex: 1, marginBottom: 30 }}>
<View style={{marginTop: 120}}>
<Text style={titleText}>INICIAR SESIÓN</Text>
<View style={section}>
<View style={iconContainer}>
<Ionicons
name={'ios-person'}
size={26}
style={{ color: '#fff', alignSelf: 'center' }}
/>
</View>
<View style={inputContainer}>
<Input
placeholder="Usuario"
value={username}
onChangeText={username => this.setState({ username })}
/>
</View>
</View>
<View style={section}>
<View style={iconContainer}>
<Ionicons
name={'ios-lock'}
size={26}
style={{ color: '#fff', alignSelf: 'center' }}
/>
</View>
<View style={inputContainer}>
<Input
secureTextEntry
placeholder="Contraseña"
value={password}
onChangeText={password => this.setState({ password })}
/>
</View>
</View>
</View>
</ImageBackground>
</View>
<KeyboardAvoidingView
behavior="padding"
keyboardVerticalOffset={30}
>
<TextLink style={{ }} onPress={this.props.formSwitch}>
Aún no estas registrado? Regístrate
</TextLink>
<TextLink style={{ }} onPress={this.props.forgotPassword}>
Olvidaste tu contraseña?
</TextLink>
<Text style={errorTextStyle}>
{error}
</Text>
{!loading ?
<Button onPress={this.loginUser}>
Ingresar
</Button>
:
<Loading size={'large'} />}
</KeyboardAvoidingView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
form: {
flex: 0.8
},
section: {
flexDirection: 'row',
backgroundColor: '#eee',
borderRadius: 3,
marginTop: 10,
height: 40,
marginLeft: '10%',
marginRight: '10%',
},
titleText: {
color: '#fff',
alignSelf: 'center',
fontSize: 20,
marginBottom: 10
},
errorTextStyle: {
alignSelf: 'center',
fontSize: 18,
color: 'red'
},
iconContainer: {
flex: 0.1,
height: 40,
borderRadius: 3,
alignSelf: 'center',
justifyContent: 'center',
backgroundColor: 'orange',
},
inputContainer: {
flex: 0.8,
alignSelf: 'flex-start',
marginLeft: -70,
}
});
export { Login };
Inside App.js you never change loading to false so the render method never gets to any of the other conditions. Once you have received the token you need to update state and change loading.

How to post data through api in react-native/redux?

I am a beginner with react-native/redux, could not find a simple to use example of how to use an api call to post data in a redux app.So I tried doing mySelf. For backend I'm using express,nodejs,mongodb. If possible then give some reference of example.
type.js
export const POST_BOOKS_SUCCESS = "POST_BOOKS_SUCCESS"
BookAction.js
import {
POST_BOOKS_SUCCESS
} from "./types";
export const postBooksSuccess = ({ prop, value}) => ({
type:POST_BOOKS_SUCCESS,
payload:{ prop, value}
});
export const createBooks = ({title,description}) => {
console.log(title,description)
return (dispatch) => {
fetch("http://localhost:3000/api/Books",{
method:"POST",
headers:{
"content-type":"application/json"
},
body:JSON.stringify({title,description})
})
.then(res=>res.json())
.then(post => dispatch(postBooksSuccess({title,description})))
}
}
AddBookReducer.js
import {
POST_BOOKS_SUCCESS
} from "../actions/types";
const INITIAL_STATE = {
title:"",
description:""
};
export default (state = INITIAL_STATE, action)=>{
console.log(action);
switch(action.type){
case POST_BOOKS_SUCCESS:
return { ...state, [action.payload.prop]: action.payload.value }
default:
return state;
}
};
Addbook.js
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
KeyboardAvoidingView,
ScrollView,
TextInput,
TouchableOpacity
} from 'react-native';
import { connect } from 'react-redux';
import createBooks from "../redux/actions/BooksActions";
class AddBooks extends Component {
static navigationOptions = ({navigation}) => ({
// title: 'Add books',
headerTintColor: '#ffffff',
headerStyle: {
backgroundColor: '#2F95D6',
borderBottomColor: '#ffffff',
borderBottomWidth: 3,
},
headerTitleStyle: {
fontSize: 18,
},
});
onButtonPress() {
const { title, description } = this.props;
this.props.createBooks({ title, description })
}
render() {
return (
<View style={styles.container}>
<KeyboardAvoidingView
behavior="padding"
style={styles.container}>
<ScrollView>
<View>
<TextInput style={styles.textInput}
placeholder="Title"
placeholderTextColor="black"
underlineColorAndroid="rgba(0,0,0,0)"
onChangeText={text => this.props.createBooks({
prop:"title", value: text })}
value={this.props.title}
/>
</View>
<View>
<TextInput style={styles.textInput}
placeholder="Description"
placeholderTextColor="black"
underlineColorAndroid="rgba(0,0,0,0)"
onChangeText={text => this.props.createBooks({ prop:"description", value: text })}
value={this.props.description}
/>
</View>
<TouchableOpacity
style={styles.button}
onPress={this.onButtonPress.bind(this)}
>
<Text style={styles.buttonText}>
Submit
</Text>
</TouchableOpacity>
</ScrollView>
</KeyboardAvoidingView>
</View>
);
}
}
mapStateToProps = (state) => {
const {title,description} = state.addBookReducers;
return {
title,
description
}
}
export default connect(mapStateToProps,{createBooks})(AddBooks)
const styles = StyleSheet.create({
container:{
backgroundColor:"#EBF5FB",
flex:1
},
textInput:{
marginTop: 10,
fontSize:20,
height:50,
borderColor:"black",
borderWidth: 1,
width:"100%"
},
button:{
width:"100%",
backgroundColor: "#19B5FE",
marginVertical: 10,
paddingVertical: 16,
borderRadius: 30,
},
buttonText:{
fontSize:16,
fontWeight:"500",
textAlign:"center",
color:"black"
},
})
reducer/index.js
import { combineReducers } from "redux";
import BookReducers from "./BooksReducers";
import AddBookReducers from "./AddBookReducers";
export default combineReducers({
bookReducers: BookReducers,
addBookReducers: AddBookReducers
})

Not getting values in props when state get changed

I am new to react-native redux , i am updating my old code which i build by using flux pattern in Redux architecture , i am learning the usage of store , thunk , reducers and Actions , Here is some of my classes which i updated :-
HomeScreenClass :-
import React, { Component } from "react";
import {
StyleSheet,
View,
StatusBar,
ActivityIndicator,
Modal,
Platform,
Image,
ScrollView,
TouchableOpacity
} from "react-native";
import { Card } from "native-base";
import NavigationDrawer from "../../component/navigationDrawerComponent/NavigationDrawer";
import CategoryProductList from "../HomeScreen/screens/CategoryProducts";
import CustomText from "../../component/customComponent/CustomText";
import ProductScreen from "./screens/ProductScreen";
import ProductDetailScreen from "./screens/ProductDetailScreen";
import PopUpMenu from "../../component/navigationDrawerComponent/PopUpMenu";
import { Font } from "expo";
import LoginScreen from "../AuthScreen/LoginScreen";
import SignUp from "../AuthScreen/SignUpScreen";
import WebApi from "../../component/webServiceComponent/WebServiceHandler";
import ForgotPassword from "../AuthScreen/ForgotPassword";
import SignUpScreen from '../AuthScreen/SignUpScreen';
import ProfileScreen from "./screens/ProfileScreen";
import ChangePassword from "../AuthScreen/ChangePassword";
import EditProfileScreen from "./screens/EditProfileScreen";
import HtmlView from "./screens/HtmlView";
import OfflineNotice from "../../component/internetCheckComponent/OfflineNotice";
import { createRouter, NavigationProvider } from "#expo/ex-navigation";
import metrics from "../../component/displaySizeComponent/metrics";
import { connect } from 'react-redux';
import { HitAllApis} from '../../actions/ApiCallActions';
var self;
export const Router = createRouter(() => ({
about: () => AboutScreen,
products: () => ProductScreen,
aboutUs: () => AboutUs,
terms: () => Terms,
rateUs: () => RateUs,
productDetails: () => ProductDetailScreen,
ProductListing: () => CategoryProductList,
feedback: () => Feedback,
htmlView: () => HtmlView,
loginScreen: () => LoginScreen,
signUpScreen: () => SignUpScreen,
profileScreen: () => ProfileScreen,
editProfileScreen: () => EditProfileScreen,
forgotPasswordScreen: () => ForgotPassword,
changePassword: () => ChangePassword
}));
class HomeScreen extends Component {
constructor(props) {
super(props);
this.state={
modalVisible: false,
loaded: false
}
self = this;
}
componentWillMount() {
console.disableYellowBox = true;
self._loadFontsAsync();
const {dispatch} = this.props;
dispatch(HitAllApis());
}
componentDidMount() {
console.log("component*****" , this.props);
}
closeModal() {
this.setState({ modalVisible: false });
}
openModal() {
if (this.state.modalVisible) {
this.setState({ modalVisible: false });
} else {
this.setState({ modalVisible: true });
}
}
_loadFontsAsync = async () => {
await Font.loadAsync({
futuraLigtBt: require("../../fonts/futuraLightBt.ttf")
});
this.setState({ loaded: true });
};
render() {
console.log("under Render ", this.props)
if (!this.props.showData || !this.state.loaded) {
return (
<View style={{ flex: 1 }}>
<Image
style={{
height: metrics.DEVICE_HEIGHT + 24,
width: metrics.DEVICE_WIDTH
}}
source={require("../../assets/splash.png")}
/>
<ActivityIndicator
color="white"
style={styles.activityIndicator}
size="small"
animating={this.props.isLoading}
/>
<OfflineNotice />
</View>
);
}
return (
<View style={styles.container}>
<NavigationProvider router={Router}>
<StatusBar barStyle="default" hidden={false} />
<NavigationDrawer
openMenu={() => this.openModal()}
disableBack={true}
magentoData={this.props.magentoData}
bannerData={this.props.bannerData}
categoryList={this.props.categoryList}
/>
</NavigationProvider>
<Modal
transparent={true}
visible={this.state.modalVisible}
animationType={"none"}
onRequestClose={() => this.closeModal()}
>
<View style={styles.modalContainer}>
<View style={styles.modalInnerContainer}>
<TouchableOpacity
style={styles.navBar}
onPress={() => this.closeModal()}
/>
<View style={{ flex: 1, backgroundColor: "white" }}>
<Card>
<ScrollView showsVerticalScrollIndicator={false}>
<View style={styles.scrollView}>
<PopUpMenu
popUpList={this.state.popUpPageData}
closePopUp={() => this.closeModal()}
/>
</View>
</ScrollView>
</Card>
</View>
</View>
<TouchableOpacity
style={{ flex: 0.5, color: "transparent" }}
onPress={() => this.closeModal()}
/>
</View>
</Modal>
<OfflineNotice />
</View>
);
}
}
function mapStateToProps(state) {
//const { magentoData: [],showData,isLoading,popUpPageData: [],categoryList: [],bannerData: [],loaded,modalVisible} = state
return {
state
}
}
export default connect(mapStateToProps)(HomeScreen)
const styles = StyleSheet.create({
modalInnerContainer: {
flex: 0.5,
justifyContent: "center",
backgroundColor: "transparent",
flexDirection: "column"
},
container: { flex: 1, justifyContent: "center", alignItems: "center" },
activityIndicator: { position: "absolute", bottom: 20, alignSelf: "center" },
navBar: {
...Platform.select({
ios: {
height: 63
},
android: {
height: 55
}
}),
color: "transparent"
},
container: {
flex: 1,
backgroundColor: "white",
alignItems: "center",
justifyContent: "center"
},
scrollView: {
flex: 1,
borderRadius: 3,
justifyContent: "flex-start",
backgroundColor: "white",
shadowColor: "black",
shadowOpacity: 0.2,
shadowRadius: 3,
shadowOffset: {
height: 0,
width: 0
}
},
modalContainer: {
flex: 1,
flexDirection: "column",
justifyContent: "center",
backgroundColor: "transparent"
}
});
In the above class i have used Ex-natvigation , i have connected this class with Reducer.In Above when i am trying to update connection line by export default connect(mapStateToProps,{HitAllApis})(HomeScreen) , it shows me syntax error.
Here is what my Action class looks like :-
import * as types from '../types/ActionTypes'
import WebApi from "../component/webServiceComponent/WebServiceHandler";
function getCategorylisting() {
console.log('category');
return WebApi.GetApihit("/restapi/index/CategoryListing", null);
}
function getdashboard() {
console.log('das');
return WebApi.GetApihit("/restapi/index/getdashboard", null);
}
function getBanner() {
console.log('Banner');
return WebApi.GetApihit("/bannersliderapp/banner/banner", null);
}
function getStaticPages() {
return WebApi.GetApihit("/restapi/staticpages/getPages/", null);
}
export function HitAllApis (){
return function (dispatch) {
WebApi.fetchHeader().then(
function () {
Promise.all([
getCategorylisting(),
getdashboard(),
getBanner(),
getStaticPages()
]).then(function (response) {
dispatch({ type: types.Api_Response_case, data: response });
}, function (Error) {
dispatch({ type: types.Api_Request_case, data: response });
});
},
function (error) {
console.log(error);
}
);
}
}
I have requirement that i need to get data from multiple Api's , so i use promise in the Action class and grab data in one single response Object
My Store class :-
import {createStore, applyMiddleware} from 'redux';
import thunkMiddleware from 'redux-thunk';
import rootReducer from '../reducers/index';
const createStoreWithMiddleware = applyMiddleware(thunkMiddleware)(createStore);
export default function configureStore(initialState) {
const store = createStoreWithMiddleware(rootReducer, initialState);
return store;
}
My Reducer class :-
import * as type from '../types/ActionTypes'
const initialState =({
magentoData: [],
showData: false,
isLoading: false,
popUpPageData: [],
categoryList: [],
bannerData: []
})
export default function DashBoardData(state = initialState, action = {}) {
switch (action.type) {
case type.Api_Request_case:
return state.isLoading = true;
case type.Api_Response_case:
state.isLoading = false;
state.showData=true;
state.categoryData = action.data[0];
state.magentoData = action.data[1];
state.bannerData = action.data[2];
state.popUpPageData = action.data[3];
// console.log('categoryData****', state.categoryData);
// console.log('magentoData****', state.magentoData);
// console.log('bannerData****', state.bannerData);
// console.log('popUpPageData****', state.popUpPageData);
return {...state};
default:
return state
}
}
And this is what i am getting inside my console.log("under Render ", this.props) :-
Object {
"dispatch": [Function anonymous],
"state": Object {
"DashBoardData": Object {
"bannerData": Array [],
"categoryList": Array [],
"isLoading": false,
"magentoData": Array [],
"popUpPageData": Array [],
"showData": false,
},
},
}
I might be doing wrong , please let me know is my approach is fine or i need to implement this in some other way , If i am doing anything wrong here Please let me know my mistake so that i can understand it more clearly.
Any Help would be greatly Appreciated!!!
Thanks
React re-renders when it determines that the old state is different from the new state. But you're modifying the old state and then copying it into the new state you return, so it thinks nothing has changed.
Your reducer should only read from the state object, it should not make modifications. For example:
export default function DashBoardData(state = initialState, action = {}) {
switch (action.type) {
case type.Api_Request_case:
return {
...state, // old state is NOT modified
isLoading: true // this is only set for the NEW state
};
case type.Api_Response_case:
return {
...state, // initially use what's in the OLD state,
isLoading: false, // then include the vales you are changing.
showData: true,
categoryData: action.data[0],
magentoData: action.data[0],
bannerData: action.data[0],
popUpPageData: action.data[0],
default:
// this REALLY means nothing has changed,
// React will not re-render
return state;
}
}

Redux-form, onChange(value) returns undefined, custom Radio component

I am using Redux-form with a custom Radio Group and Button components. When i select a radio button, redux-logger seems to show that the state is updated with the correct values. However checked always returns false, and so the radio button style never gets updated.
console.log(value) returns the correct value
console.log(onChange(value) always returns undefined
console.log(checked) always returns false
RadioGroup.js
import React from 'react';
import PropTypes from 'prop-types';
import { View, Text, StyleSheet } from 'react-native';
import RadioButton from '../components/RadioButton';
import { COLOR_PRIMARY } from '../constants';
const styles = StyleSheet.create({
errorStyle: {
color: COLOR_PRIMARY,
},
});
const RadioGroup = (props) => {
const { radios, input: { value, onChange }, meta: { touched, error } } = props;
return (
<View>
{radios.map(radio => (
<RadioButton
key={radio.label}
{...radio}
onChange={onChange}
checked={radio.value === value}
/>
))}
{touched &&
(error && (
<View>
<Text style={styles.errorStyle}>{error}</Text>
</View>
))}
</View>
);
};
RadioGroup.propTypes = {
radios: PropTypes.arrayOf(
PropTypes.shape({
label: PropTypes.string.isRequired,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]).isRequired,
}),
).isRequired,
meta: PropTypes.shape({
touched: PropTypes.bool.isRequired,
error: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
}).isRequired,
input: PropTypes.shape({
value: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]).isRequired,
onChange: PropTypes.func.isRequired,
}).isRequired,
};
export default RadioGroup;
RadioButton.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { TouchableOpacity, View, Text, StyleSheet } from 'react-native';
import { COLOR_PRIMARY, TEXT_PRIMARY } from '../constants';
const styles = StyleSheet.create({
container: {
marginBottom: 20,
flexDirection: 'row',
alignItems: 'center',
},
circle: {
height: 24,
width: 24,
borderRadius: 12,
borderWidth: 2,
borderColor: COLOR_PRIMARY,
alignItems: 'center',
justifyContent: 'center',
},
circleFilled: {
height: 14,
width: 14,
borderRadius: 7,
backgroundColor: COLOR_PRIMARY,
},
labelStyle: {
color: TEXT_PRIMARY,
marginLeft: 10,
marginRight: 10,
},
});
export default class RadioButton extends Component {
handlePress = () => {
const { value, onChange, checked } = this.props;
onChange(value);
console.log(onChange(value));
console.log(value);
console.log(checked);
};
render() {
const { checked, label } = this.props;
return (
<View style={styles.container}>
<TouchableOpacity onPress={this.handlePress} style={styles.radioStyle}>
<View style={styles.circle}>
<View style={checked ? styles.circleFilled : null} />
</View>
</TouchableOpacity>
<Text style={styles.labelStyle}>{label}</Text>
</View>
);
}
}
RadioButton.propTypes = {
checked: PropTypes.bool.isRequired,
label: PropTypes.string.isRequired,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]).isRequired,
onChange: PropTypes.func.isRequired,
};
Form.js
<Field
name="sex"
radios={[{ label: 'Male', value: 'Male' }, { label: 'Female', value: 'Female' }]}
component={RadioGroup}
/>
So is there some problem with how i am using onChange?