這個也是一個基礎項目
地址以下https://github.com/ndlonghi/react-native-template-app
點擊登錄跳轉到首頁
分析代碼如
react-native-template-app/src/components/loading/index.js
loading效果react
import React from 'react'; import { ActivityIndicator, Image, StyleSheet, View } from 'react-native'; function Loading(props) { return ( <View style={styles.container} > <Image source={require('../../assets/imgs/logo.png')} style={styles.logo} /> <ActivityIndicator/> </View> ) } const styles = StyleSheet.create({ container: {}, logo: {} }); export default Loading;
//app.js import React, {Component} from 'react'; import {Provider} from 'react-redux'; import {PersistGate} from 'redux-persist/integration/react'; //redux //loading //跳轉路由 import {store, persistor} from "./src/store"; import Loading from "./src/components/loading/index"; import RootNavigator from "./src/navigation/containers"; export default class App extends Component { render() { return ( <Provider store={store} > <PersistGate loading={<Loading/>} persistor={persistor} > <RootNavigator/> </PersistGate> </Provider> ); } }
src/store.jsgit
import { applyMiddleware, createStore } from 'redux'; import {persistStore, persistReducer} from 'redux-persist'; import storage from 'redux-persist/lib/storage'; import {createReactNavigationReduxMiddleware} from 'react-navigation-redux-helpers'; import rootReducer from './reducers'; const persistConfig = { key: 'root', storage, blacklist: ['navigation'] }; const persistedReducer = persistReducer(persistConfig, rootReducer); const navigationMiddleware = createReactNavigationReduxMiddleware( 'root', state => state.navigation ); const store = createStore( persistedReducer, applyMiddleware(navigationMiddleware) ); const persistor = persistStore(store); export {store, persistor};
src/reducers/index.jsgithub
import {combineReducers} from 'redux'; import auth from "../services/auth/reducers"; import navigation from "../navigation/reducers"; export default combineReducers({ auth, navigation });
數據處理
src/services/api/index.jsjson
import {Environments} from "../../environments/environments"; import type {Credentials} from "../../models/credentials"; import type {AuthObject} from "../../models/auth-object"; import type {ApiErrorResponse} from "../../models/api-error-response"; class Api { static getBackendConfig() { return Environments[Environments.env].backend; } handleError(error: any): ApiErrorResponse { let errorResponse: ApiErrorResponse = { error: error, text: 'An error ocurred. Please try again later.' }; return errorResponse; } async get(url: string): any | ApiErrorResponse { return fetch(url, { method: 'GET' }) .then((response) => { return response.json(); }) .catch((error: any) => { reject(this.handleError(error)); }) } async post(url: string, data: any): any | ApiErrorResponse { return fetch(url, { method: 'POST', body: JSON.stringify(data) }) .then((response) => { return response.json(); }) .catch((error: any) => { reject(this.handleError(error)); }) } async login(credentials: Credentials): Promise<AuthObject | ApiErrorResponse> { //const query = await this.post(Api.getBackendConfig().url + Endpoints.LOGIN, credentials); //const {data} = await query.json(); //return data; // Simulate api call return new Promise((resolve, reject) => { setTimeout(() => { resolve({token: 'sanoteru'}); }, 1000); }) } } const Endpoints = { LOGIN: '' }; export default new Api();
//src/services/auth/actions/action-tyes.js export const SET_AUTH = 'SET_AUTH'; export const REMOVE_AUTH = 'REMOVE_AUTH';
///src/services/auth/actions/index.js import { REMOVE_AUTH, SET_AUTH } from "./action-tyes"; import type {AuthObject} from "../../../models/auth-object"; export const setAuth = (authObject: AuthObject) => ({ type: SET_AUTH, payload: { authObject } }); export const removeAuth = () => ({ type: REMOVE_AUTH });
//src/services/auth/reducers/index.js import { REMOVE_AUTH, SET_AUTH } from "../actions/action-tyes"; function auth(state = {}, action) { switch (action.type) { case SET_AUTH: { return { authObject: action.payload.authObject } } case REMOVE_AUTH: { return { authObject: null } } default: { return state; } } } export default auth;
//src/screens/loading.js import React, {Component} from 'react'; import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; import {navigateToHome, navigateToLogin} from "../navigation/actions/index"; import LoadingLayout from '../components/loading/index'; const mapStateToProps = state => { return { auth: state.auth } }; const mapDispatchToProps = dispatch => { return bindActionCreators({navigateToLogin, navigateToHome}, dispatch); }; class Loading extends Component { componentDidMount() { this.redirect(); } redirect = () => { if (this.props.auth.authObject) { this.props.navigateToHome(); } else { this.props.navigateToLogin(); } }; render() { return <LoadingLayout/> } } export default connect(mapStateToProps, mapDispatchToProps)(Loading);
//src/screens/login.js import React, {Component} from 'react'; import { Button, Image, SafeAreaView, StyleSheet, TextInput, View } from 'react-native'; import {connect} from 'react-redux'; import {bindActionCreators} from "redux"; import {removeAuth, setAuth} from "../services/auth/actions/index"; import {navigateToHome} from "../navigation/actions/index"; import type {AuthObject} from "../models/auth-object"; import type {ApiErrorResponse} from "../models/api-error-response"; import Api from '../services/api/index'; const mapDispatchToProps = dispatch => { return bindActionCreators({setAuth, removeAuth, navigateToHome}, dispatch); }; class Login extends Component { handleSubmit = () => { Api.login({ email: 'mobile@4rsoluciones.com', password: 'aoeu' }) .then((auth: AuthObject) => { this.props.setAuth(auth); this.props.navigateToHome(); }) .catch((error: ApiErrorResponse) => { this.props.removeAuth(); }) }; render() { return ( <SafeAreaView style={styles.container}> <View> <Image source={require('../assets/imgs/logo.png')} style={styles.logo} /> <TextInput style={styles.input} placeholder="Username" placeholderTextColor="white" /> <TextInput style={styles.input} placeholder="Password" placeholderTextColor="white" secureTextEntry={true} /> <Button onPress={this.handleSubmit} title="Log in" /> </View> </SafeAreaView> ) } } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: 'white', }, logo: { width: 200, height: 80, resizeMode: 'contain', marginBottom: 10, }, input: { marginBottom: 10, width: 250, height: 50, paddingHorizontal: 10, borderRadius: 5, backgroundColor: '#838383', color: 'white', } }); export default connect(null, mapDispatchToProps)(Login);
login引用的是這裏的apiredux
import {Environments} from "../../environments/environments"; import type {Credentials} from "../../models/credentials"; import type {AuthObject} from "../../models/auth-object"; import type {ApiErrorResponse} from "../../models/api-error-response"; class Api { static getBackendConfig() { return Environments[Environments.env].backend; } handleError(error: any): ApiErrorResponse { let errorResponse: ApiErrorResponse = { error: error, text: 'An error ocurred. Please try again later.' }; return errorResponse; } async get(url: string): any | ApiErrorResponse { return fetch(url, { method: 'GET' }) .then((response) => { return response.json(); }) .catch((error: any) => { reject(this.handleError(error)); }) } async post(url: string, data: any): any | ApiErrorResponse { return fetch(url, { method: 'POST', body: JSON.stringify(data) }) .then((response) => { return response.json(); }) .catch((error: any) => { reject(this.handleError(error)); }) } async login(credentials: Credentials): Promise<AuthObject | ApiErrorResponse> { //const query = await this.post(Api.getBackendConfig().url + Endpoints.LOGIN, credentials); //const {data} = await query.json(); //return data; // Simulate api call return new Promise((resolve, reject) => { setTimeout(() => { resolve({token: 'sanoteru'}); }, 1000); }) } } const Endpoints = { LOGIN: '' }; export default new Api();
//src/screens/home.js import React, {Component} from 'react'; import { Button, SafeAreaView, StyleSheet, Text, View } from 'react-native'; import {connect} from 'react-redux'; import {bindActionCreators} from "redux"; import {removeAuth} from "../services/auth/actions/index"; import {navigateToLogin} from "../navigation/actions/index"; const mapDispatchToProps = dispatch => { return bindActionCreators({removeAuth, navigateToLogin}, dispatch); }; class Home extends Component { handleLogout = () => { this.props.removeAuth(); this.props.navigateToLogin(); }; render() { return ( <SafeAreaView style={styles.container}> <View> <Text>This is the home</Text> <Button onPress={this.handleLogout} title="Log out" /> </View> </SafeAreaView> ) } } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: 'white', } }); export default connect(null, mapDispatchToProps)(Home);
關於navigation部分還進行了不少處理,項目不容易啊~react-native