Open JNUfeatherwit opened 6 years ago
本文介绍我们项目用到的一种登录验证的方案。 完成一套登录流程需要解决以下的问题:
await this.props.appStore.login(this.form)//登录
//login.js //@flow import React, { Component } from 'react' import { StyleSheet, View } from 'react-native' import { Button, Toast, WhiteSpace, WingBlank } from 'antd-mobile-rn' import { inject, observer } from 'mobx-react/native' import { observable } from 'mobx' import AppStore from '../../store/AppStore' import validator from 'mobx-form-validator' import type { NavigationScreenProp } from 'react-navigation' import { FormItem, FormProvider } from 'components/Form'
type Props = { appStore: AppStore, navigation: NavigationScreenProp<*> }
@inject('appStore') @observer class App extends Component { form = new LoginForm()
navigateHome = async () => { // 获取用户配置信息 await this.props.appStore.getUserConfiguration() this.props.navigation.navigate('Home') }
loginSuccess = async () => { // 登录成功获取用户登录信息 await this.props.appStore.getCurrentLoginInformation() await this.navigateHome() }
login = async () => { if (this.form.validateFields()) { try { await this.props.appStore.login(this.form) await this.loginSuccess() } catch (e) { console.warn(e) Toast.fail('用户名或密码错误!', 2, undefined, false) } } else { Toast.fail('请输入正确的用户名和密码!', 2, undefined, false) } }
render() { return (
)
} }
const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center' } })
class LoginForm { @observable @validator([ { required: true, message: '用户名不能为空' } ]) userName = ''
@observable @validator([ { required: true, message: '密码不能为空' } ]) password = '' }
export default App
先自定义一个class LoginForm作为表单的数据对象,用@validator修饰每个属性赋予其验证的功能,再将这个form传递给FormProvider。
//FormProvider import React, { Component } from 'react' import { View } from 'react-native' import { observer } from 'mobx-react' import { observable, action } from 'mobx' import PropTypes from 'prop-types'
@observer class FormProvider extends Component { static propTypes = { form: PropTypes.object.isRequired }
@observable validateStatus = false
constructor(props, context) { super(props, context)
/** * 校验全部组件 */ this.props.form.validateFields = action(() => { this.validateStatus = true return this.props.form.isValid }) /** * 获取全部组件的值 */ this.props.form.getFieldsValue = () => { return this.props.form }
}
render() { const { form, children } = this.props return (
export default FormProvider
Provider是一个总的表单组件,它赋予传递过来的form两个方法:验证和获取表单,加载FormItem表单项组件
//FormItem import React, { Component } from 'react' import PropTypes from 'prop-types' import { observer } from 'mobx-react' import { observable, action } from 'mobx' import camelCase from 'camelcase' import { Toast, InputItem } from 'antd-mobile-rn'
@observer class FormItem extends Component { static propTypes = { form: PropTypes.object, name: PropTypes.string.isRequired, placeholder: PropTypes.string, type: PropTypes.string, editable: PropTypes.bool, disabled: PropTypes.bool, clear: PropTypes.bool, extra: PropTypes.string, onExtraClick: () => {}, labelNumber: PropTypes.number, labelPosition: PropTypes.string, textAlign: PropTypes.string, last: PropTypes.bool }
validateKey = camelCase(validateError ${this.props.name})
validateError ${this.props.name}
@observable focus = false
showError = () => { Toast.fail(this.props.form[this.validateKey], 2, undefined, false) }
@action onChangeText = text => { const { name } = this.props this.props.form[name] = text }
@action onFocus = () => { if (!this.focused) { this.focused = true } }
render() { const { name, form, validateStatus, children, placeholder, type, editable, clear, disabled, extra, onExtraClick, labelNumber, labelPosition, textAlign, last,
...otherProps } = this.props const value = form[name] // 是否校验通过 const isError = (!!form[this.validateKey] && this.focused) || (!!form[this.validateKey] && validateStatus) return ( <InputItem {...otherProps} value={value} error={isError} onFocus={this.onFocus} onChange={this.onChangeText} onErrorClick={this.showError} placeholder={placeholder} type={type} editable={editable} clear={clear} disabled={disabled} extra={extra} onExtraClick={onExtraClick} labelNumber={labelNumber} labelPosition={labelPosition} textAlign={textAlign} last={last} > {children} </InputItem> )
export default FormItem
form[this.validateKey]是表单项对应的报错信息,isError规定了只有在触发了onfocus或validateFields()且不报错的时候才会在输入框右边弹出小感叹号, showError规定了点击感叹号时弹出一个Toast。 ### 3、如何登录验证 不同于输入验证,登录验证不仅要先初步判断输入项是否为空,而且要进行服务端验证,这就需要用到异步的方法,代码如下:
先是调用this.form.validateFields()进行初步判断,然后调用异步方法login进行登录,这是登录的具体代码
@loading @action async login(user: { userName: string, password: string }) { const { accessToken, userId } = await fech(url,{userName,password}) await setStorageValue('Authorization', accessToken) //存储在本地存储 return userId }
先是获取用户数据,再把登录权限存在本地,之后第二次登录可以直接跳过登录。 登录成功后调用loginSuccess(),代码如下:
loginSuccess = async () => { // 登录成功获取用户登录信息 await this.props.appStore.getCurrentLoginInformation() //获取当前用户的信息,判断是否在登录状态 await this.navigateHome() //跳转Home 页面 }
本文介绍我们项目用到的一种登录验证的方案。 完成一套登录流程需要解决以下的问题:
1、登录的用户信息和行为用什么形式保存在内存中,如何将用户信息传播到所有需要使用到它的组件
2、如何进行输入验证
type Props = { appStore: AppStore, navigation: NavigationScreenProp<*> }
@inject('appStore') @observer class App extends Component {
form = new LoginForm()
navigateHome = async () => { // 获取用户配置信息 await this.props.appStore.getUserConfiguration() this.props.navigation.navigate('Home') }
loginSuccess = async () => { // 登录成功获取用户登录信息 await this.props.appStore.getCurrentLoginInformation() await this.navigateHome() }
login = async () => { if (this.form.validateFields()) { try { await this.props.appStore.login(this.form) await this.loginSuccess() } catch (e) { console.warn(e) Toast.fail('用户名或密码错误!', 2, undefined, false) } } else { Toast.fail('请输入正确的用户名和密码!', 2, undefined, false) } }
render() { return (
} }
const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center' } })
class LoginForm { @observable @validator([ { required: true, message: '用户名不能为空' } ]) userName = ''
@observable @validator([ { required: true, message: '密码不能为空' } ]) password = '' }
export default App
//FormProvider import React, { Component } from 'react' import { View } from 'react-native' import { observer } from 'mobx-react' import { observable, action } from 'mobx' import PropTypes from 'prop-types'
@observer class FormProvider extends Component { static propTypes = { form: PropTypes.object.isRequired }
@observable validateStatus = false
constructor(props, context) { super(props, context)
}
render() { const { form, children } = this.props return (
} }
export default FormProvider
//FormItem import React, { Component } from 'react' import PropTypes from 'prop-types' import { observer } from 'mobx-react' import { observable, action } from 'mobx' import camelCase from 'camelcase' import { Toast, InputItem } from 'antd-mobile-rn'
@observer class FormItem extends Component { static propTypes = { form: PropTypes.object, name: PropTypes.string.isRequired, placeholder: PropTypes.string, type: PropTypes.string, editable: PropTypes.bool, disabled: PropTypes.bool, clear: PropTypes.bool, extra: PropTypes.string, onExtraClick: () => {}, labelNumber: PropTypes.number, labelPosition: PropTypes.string, textAlign: PropTypes.string, last: PropTypes.bool }
validateKey = camelCase(
validateError ${this.props.name}
)@observable focus = false
showError = () => { Toast.fail(this.props.form[this.validateKey], 2, undefined, false) }
@action onChangeText = text => { const { name } = this.props this.props.form[name] = text }
@action onFocus = () => { if (!this.focused) { this.focused = true } }
render() { const { name, form, validateStatus, children, placeholder, type, editable, clear, disabled, extra, onExtraClick, labelNumber, labelPosition, textAlign, last,
} }
export default FormItem
login = async () => { if (this.form.validateFields()) { try { await this.props.appStore.login(this.form) await this.loginSuccess() } catch (e) { console.warn(e) Toast.fail('用户名或密码错误!', 2, undefined, false) } } else { Toast.fail('请输入正确的用户名和密码!', 2, undefined, false) } }
@loading @action async login(user: { userName: string, password: string }) { const { accessToken, userId } = await fech(url,{userName,password}) await setStorageValue('Authorization', accessToken) //存储在本地存储 return userId }
loginSuccess = async () => { // 登录成功获取用户登录信息 await this.props.appStore.getCurrentLoginInformation() //获取当前用户的信息,判断是否在登录状态 await this.navigateHome() //跳转Home 页面 }