>Target:
一种通用方法,它通过我的网络类调用 Web 服务显示微调器,同时在完成后将其删除,然后通过显示警报最终处理错误(如果有(,否则将响应发送回我的调用类。
我做了什么:我编写了以下方法,即在我的基类中,所有类都将具有此方法。
问题:由于调用setState会更新屏幕,因此任何警报(错误/成功(都会出现片刻,然后最后一个屏幕出现在前面,并且由于警报在屏幕后面,所有东西都卡住了。
要求:谁能指出我正在犯什么错误或任何如何处理这个问题的概念。
import React, { Component } from 'react'
import { View } from 'react-native'
import Network from './Network';
export default class BaseClass extends Component {
constructor() {
super()
this.state = {
spinner:false,
response:''
}
}
onPress(data){
this.setState({ spinner: true })
var net = new Network();
net.makeCall(data,function(context,err,res){
context.setState({ spinner: false })
if(err!= null){
alert('error')
}
else{
alert('sccess')
}
)
}
}
第二种方法我采用了第二种方法,但在这里得到了相同的结果。
import React, { Component } from 'react'
import { View } from 'react-native'
import Network from './Network';
export default class BaseClass extends Component {
constructor() {
super()
this.state = {
spinner:false,
response:''
}
}
onPress(data){
this.setState({ spinner: true })
var net = new Network();
net.makeCall(data,function(context,err,res){
context.setState({ spinner: false })
if(err!= null){
context.setState({ response: err })
}
else{
context.setState({ response: data })
}
)
}
componentDidUpdate(){
alert(this.state.response)
}
}
我目前的工作类,很少有类是自定义类,如屏幕,会话管理器,会话计时器,常量
"use strict";
import React, {Component} from 'react';
import Spinner from 'react-native-loading-spinner-overlay';
import Pinch from 'react-native-pinch';
import Config from './Config'
import {SessionManager} from './utilities/SessionManager';
import Constants from './utilities/Constants'
import {Platform, Alert} from 'react-native';
import {Screens} from './navigation/Screens'
import SessionTimer from './utilities/SessionTimer';
import IMEI from './utilities/IMEI'
// Check Device Info
var DeviceInfo = require('react-native-device-info');
//import Spinner from 'react-native-spinkit'
/*
this class will be used to communicate with
server and getting url params from the calling class,
handles the server error if there is no error it will
return the repsonse to the calling class
*/
export class WebServiceCallManager extends Component {
constructor(props) {
super(props);
this.state = {
visible: this.props.visible,
size: 100,
}
}
callWebService(requestAction, subAction, bodyParams, responseHandler, optionalErrHandler) {
this.setState({visible: true});//Starting the Processing indicator
let imei = null;
if (Platform.OS === 'android') {
imei = SessionManager.getSessionValue("IMEI");
}
var params = {
"Header": {
"AppVersion": DeviceInfo.getVersion(),
//"IMEI":imei,
//"DEVICE_MAKE" : (Platform.OS === 'android') ? "AN": (Platform.OS === 'ios') ? "IP" : "OT",
"Channel": (Platform.OS === 'android') ? 'MOBILE_ANDROID' : (Platform.OS === 'ios') ? "MOBILE_IOS" : null,
// DeviceInfo.getManufacturer()
// "Channel":DeviceInfo.getManufacturer(),
//"DeviceId": DeviceInfo.getUniqueID(),
// "NetworkType": "MOBILE DATA 3G",
"RequestAction": requestAction,
"SubAction": subAction,
"Token": SessionManager.getSessionValue(Constants.TOKEN),
// "Operator": "ZONG",
"CSRF": SessionManager.getSessionValue(Constants.CSRF),
//"OS": DeviceInfo.getSystemVersion(),
"DeviceInformation": {
"IMEI": imei,
"Manufacturer": DeviceInfo.getManufacturer(),
"Model": DeviceInfo.getModel(),
"DeviceId": DeviceInfo.getUniqueID(),
"DeviceMake": (Platform.OS === 'android') ? "AN" : (Platform.OS === 'ios') ? "IP" : "OT",
"OS": DeviceInfo.getSystemVersion(),
}
},
"Body": {
"Transaction": bodyParams
}
};
var url = Config.IP;
if (url.startsWith('https')) {
this._httpsCalling(url, params, responseHandler, optionalErrHandler);
} else {
this._httpCalling(url, params, responseHandler, optionalErrHandler);
}
}
_httpsCalling(url, params, responseHandler) {
Pinch.fetch(url,
{
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(params),
sslPinning: {
cert: 'prodcer'
}
})
.then((responseResult) => {
this.setState({visible: false});// removing the Processing symbol
var result = JSON.parse(responseResult.bodyString);
var strResult = JSON.stringify(result);
if (responseResult.status == '0') {
responseHandler(strResult);
}
else {
responseHandler(strResult);
}
}).catch((err) => {
this.setState({visible: false});// removing the Processing symbol
responseHandler(err.message + '');
})
.done();
}
_httpCalling(url, params, responseHandler, optionalErrHandler) {
fetch(url,
{
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(params)
})
.then((resType) => resType.json())
.then((responseResult) => {
let timer = new SessionTimer();
timer.resetSessionTimer(0);
this.setState({visible: false});// removing the Processing symbol
SessionManager.setSessionValue(Constants.TOKEN, responseResult.Header.Cookie);
SessionManager.setSessionValue(Constants.CSRF, responseResult.Header.CSRF);
if (responseResult.Header.ResponseCode == '0') {
responseHandler(responseResult);
}
else {
if (optionalErrHandler !== undefined) {
optionalErrHandler(responseResult.Header);
}
this.errorHandler(responseResult.Header);
// responseHandler(null ,responseResult.Header.ResponseMessage);
}
}).catch((err) => {
var error = {ResponseMessage: err.message};
if (optionalErrHandler !== undefined) {
optionalErrHandler(error);
}
this.errorHandler(error);
})
.done();
}
errorHandler(errorData) {
this.setState({visible: false});// removing the Processing symbol
let msg = errorData.ResponseMessage;
let errorCode = errorData.ResponseCode;
if (errorCode == 111) {
setTimeout(
() => {
Alert.alert('Respose Error ' +
msg,
'',
[
{
text: 'OK', onPress: () => {
this.props.nav.popToRoute(Screens.LoginScreen)
}
},
],
{cancelable: false}
)
},
100
);
}
else {
setTimeout(
() => {
alert(msg)
},
100
);
}
}
render() {
return <Spinner visible={this.state.visible} itemProp='size:100'/>
}
}
编辑16 Sep 2019:
在这里,我添加了另一个类,其中我使用了上面定义的网络类,实际上它是 React 世界中的一个组件,因此在渲染方法中,我们添加了该组件并获得了该组件的引用,我们在其上调用方法callWebService()
import React, { Component } from 'react';
import { StyleSheet, Text, View, Button,Switch, Alert, Image, TouchableHighlight, Dimensions, Platform,AppState } from 'react-native';
import Constants from '.././utilities/Constants'
import {Screens} from '.././navigation/Screens'
import {ScreenClass} from '.././navigation/Screens';
import TextInputCustom from '.././components/TextInputCustom';
import {SessionManager} from '../utilities/SessionManager';
import {WebServiceCallManager} from '.././WebServiceCallManager';
import {NavigationManager} from '.././navigation/NavigationManager';
import Fingerprint from '.././fingerprint/FingerprintAndroid';
const dismissKeyboard = require('dismissKeyboard');
const { width, height } = Dimensions.get("window");
let opacity = 1;
// source address of login background image
const loginBackgroundViewImg = require('.././assets/login_box.png');
const biometricImage = require('.././assets/biometric_icon.png');
var langs = new Constants(); // language localization
/* Login View for displaying TextInputs(username, passwords),
Buttons (Login, Register) and Labels (Terms & condition , forget password)
*/
export class LoginContainer extends Component {
constructor(props){
super(props);
this.state = {
username: '' , // user33
password: '', // Awaqas@2
emptyInputFields : '',
falseSwitchIsOn : true,
phase: 'normal',
message: '',
cancelled: false
}
}
componentDidMount() {
// Fingerprint.saveCredentials("user33","Awaqas@2",()=>{
// this.setState({
// phase: 'saved',
// message: ''
// });
// },()=>{});
this.authenticate();
AppState.addEventListener("change", async(state) => {
try {
if(state === "active" && await Fingerprint.isAuthenticationCanceled()) {
this.authenticate()
}
}
catch(z) {
console.error(z)
}
})
}
async componentWillUnmount() {
try {
if(!Fingerprint.isAuthenticationCanceled()) {
//stop listening to authentication.
await Fingerprint.cancelAuthentication();
}
} catch(z) {
console.error(z);
}
}
async authenticate() {
try {
// do sanity checks before starting authentication flow.
// HIGHLY recommended in real life usage. see more on why you should do this in the readme.md
const hardware = await Fingerprint.isHardwareDetected();
const permission = await Fingerprint.hasPermission();
const enrolled = await Fingerprint.hasEnrolledFingerprints();
if (!hardware || !permission || !enrolled) {
let message = !enrolled ? 'No fingerprints registered.' : !hardware ? 'This device doesn't support fingerprint scanning.' : 'App has no permission.'
this.setState({
phase: 'fail',
message
});
return;
}
await Fingerprint.authenticate(warning => {
this.setState({
phase: 'warn',
message: warning.message
})
});
// if we got this far, it means the authentication succeeded.
this.setState({
phase: 'success',
message: ''
});
// in real life, we'd probably do something here (process the payment, unlock the vault, whatever)
// but this is a demo. so restart authentication.
// setTimeout(() => this.authenticate(), 3000);
} catch (error) {
if(error.code == Fingerprint.FINGERPRINT_ERROR_CANCELED) {
// we don't show this error to the user.
// we will check if the auth was cancelled & restart the flow when the appstate becomes active again.
return;
}
this.setState({
phase: 'fail',
message: error.message
})
}
}
buttonsHandler(type){
switch (type) {
case 'forgotpassword':
this.props.navigation.push(Screens.ForgotPasswordScreen);
break;
case 'forgotuserid':
this.props.navigation.push(Screens.ForgotUserIDScreen);
break;
case 'unlockprofile':
this.props.navigation.push(Screens.UnlockProfileScreen);
break;
case 'register':
dismissKeyboard();
this.props.navigation.push(Screens.RegistrationWelcomeScreen);
break;
case 'login':
this.loginWebServiceCall();
break;
default:
alert(type + ' is pressed');
}
}
// this will be called when user hit login button
loginWebServiceCall()
{
if(this.state.username.length === 0 && this.state.password.length === 0){
this.setState({emptyInputFields:langs.strings.login_userid_password_empty});
this.userName.textFocus();
}
else if (this.state.username.length === 0 ) {
this.setState({emptyInputFields:langs.strings.login_userid_empty});
this.userName.textFocus();
}
else if ( this.state.password.length === 0) {
this.setState({emptyInputFields:langs.strings.login_password_empty});
this.password.textFocus();
}else{
this.setState({emptyInputFields:''});
var params = {
"Password": this.state.password,
"UserName": this.state.username,
"LoginType": 'Manual',
};
this.webservicemanager.callWebService("LOGIN","TRANSACTION",params,(response) => {this.handleWebServiceCallResponse(response);});
}
}
/* handle the web service successfull response error
response will be handled inside WebServiceCallManager */
handleWebServiceCallResponse(data){
dismissKeyboard();
var userData = {
"username":this.state.username,
"password":this.state.password
}
var passwordPolicy = {
"passwordPolicy" : data.Body.Transaction.PasswordPolicy,
"passwordPolicyRegex" : data.Body.Transaction.PasswordPolicyRegex
}
SessionManager.setSessionValue(Constants.FASTTRANSFER_BENEFICIARY_BRANCH_LIST,data.Body.Transaction.BranchList);
SessionManager.setSessionValue(Constants.BENEFICIARY_COUNTRY,data.Body.Transaction.CountryList);
SessionManager.setSessionValue(Constants.BENEFICIARY_RELATIONSHIP, data.Body.Transaction.RelationList);
SessionManager.setSessionValue(Constants.LOGIN_USERDATA, userData);
SessionManager.setSessionValue(Constants.CUSTOMER_NUMBER,data.Body.Transaction.CUSTNO);
SessionManager.setSessionValue(Constants.PASSWORD_POLICY, passwordPolicy);
SessionManager.setSessionValue(Constants.SECURITY_QUESTIONS_LIST,data.Body.Transaction.Questions);
var nextScreenName = data.Body.Transaction.NextScreenName;
const SpecificScreenClass = ScreenClass.getClassFromClassName(nextScreenName);
SessionManager.setSessionValue('nextScreenName', nextScreenName);
this.props.navigation.push(SpecificScreenClass);
this.setState({
username:'',
password:'',
emptyInputFields:''
});
this.userName.textClear();
this.password.textClear();
dismissKeyboard();
}
// handling text input field focus
textHandler(){
this.password.focus();
}
onSwitchToggle(value){
if(value){
opacity = 1;
}
else{
opacity= 0.4;
}
this.setState({falseSwitchIsOn: value});
}
render(){
this.fetchCredentials(this.webservicemanager,this.handleWebServiceCallResponse.bind(this));
return(
<View style={ styles.loginView}>
<Image style={ styles.loginViewBackground} source={loginBackgroundViewImg}>
<View>
<TextInputCustom
ref ={(ref) => this.userName = ref}
placeholder={langs.strings.login_userid_placeholder}
secureTextEntry={false}
onChangeTextCallback={val => this.setState({'username' : val})}
returnKeyType="next"
textInputWidth = {((width*86)/100)}
// onEndEditingCallback = {() => this.password.textFocus()}
/>
<TextInputCustom
ref ={(ref) => this.password =ref}
placeholder={langs.strings.login_password_placeholder}
secureTextEntry={true}
onChangeTextCallback={val => this.setState({'password' : val})}
returnKeyType="done"
textInputWidth = {((width*86)/100)}
/>
<Text style={ styles.emptyInputFields}>{this.state.emptyInputFields}</Text>
</View>
<View style={ styles.middleContainerViewButtons}>
<View style={ styles.middleContainerViewButtonsBtn}>
<TouchableHighlight onPress={ () => this.buttonsHandler('login')}>
<Text style={ styles.btnTextLabels}>{langs.strings.login_btnLogin}</Text>
</TouchableHighlight>
</View>
<View style={ styles.middleContainerViewButtonsBtn}>
<TouchableHighlight onPress={() => this.buttonsHandler('register')}>
<Text style={ styles.btnTextLabels}>{langs.strings.login_btnRegister}</Text>
</TouchableHighlight>
</View>
</View>
<TouchableHighlight onPress={() => {this.buttonsHandler('forgotpassword')}} underlayColor = {'transparent'}>
<Text style={ styles.labels} >
Forogot Password
</Text>
</TouchableHighlight>
<TouchableHighlight onPress={() => {this.buttonsHandler('forgotuserid')}} underlayColor = {'transparent'}>
<Text style={ styles.labels} >
Forogot User ID
</Text>
</TouchableHighlight>
<TouchableHighlight onPress={() => this.buttonsHandler('terms')} underlayColor = {'transparent'}>
<View >
<Text style={ styles.labels}>
{langs.strings.login_txtTermsAndConditions}
</Text>
</View>
</TouchableHighlight>
<View style={styles.fingerPrintLayout}>
<TouchableHighlight underlayColor = {'transparent'}>
<View >
<Image style={styles.biometricImage} source={biometricImage}/>
</View>
</TouchableHighlight>
<View style={styles.switchRow} >
<Text style={ styles.labels} >
Enable Finger Print Login
</Text>
<Switch
onValueChange={(value) => this.onSwitchToggle(value) }
style={styles.switchControl}
value={this.state.falseSwitchIsOn} />
</View>
<Text>{this.state.message}</Text>
</View>
</Image>
<WebServiceCallManager visible={false} nav = {this.props.navigation} ref={ (input) => {this.webservicemanager = input;}}/>
</View>
);
}
fetchCredentials(web,resHandler) {
if(this.state.phase === 'success') {
Fingerprint.fetchCredentials(
(...res) => {
console.log(res);
var params = {
"Password": res[1],
"UserName": res[0],
"LoginType": 'Biometric'
};
this.setState({username:params.UserName,password:params.Password,phase:''})
this.webservicemanager.callWebService("LOGIN","TRANSACTION",params,(response) => {this.handleWebServiceCallResponse(response);},
(err)=> {
this.authenticate();});
},
(res) => {
console.log(res);
return null;
}
);
}
}
} // end of class