react高阶组件的使用
为了提高代码的复用在react中我们可以使用高阶组件
1.添加高阶组件
高阶组件主要代码模板HOC.js
export default (WrappedComponent) => { return class extends Component { constructor(props) { super(props) this.state = { //定义可复用的状态 } this.getCode = this.getCode.bind(this) } componentWillMount() { } //定义可复用的方法 getCode(mobile) { ... } postVcode(mobile) { ... } render() { return ( <div> <WrappedComponent getCode={this.getCode} state={this.state} {...this.props}/> </div> ) } } }
注:其中<WrappedComponent />的自定义属性getCode与state传递了对外可以用的方法与属性
2.在其他组件中使用高阶组件
register.js
import HOC from 'common/js/HOC' class Register extends Component{ ... ... } export default HOC(Register)
或者也可以使用装饰器语法书写
import HOC from 'common/js/HOC' @HOC class Register extends Component{ ... } export default Register
3.完整示例代码
例如 发送短信验证码功能在注册于忘记密码2个组件中都用到了,我们可以把它抽离到HOC中
HOC.js
import React, {Component} from 'react' import axios from 'axios' import qs from 'qs' import { noToken } from './config' import { loadToken } from 'common/js/cache' import { url } from 'common/js/config' let token = loadToken() console.log('token', token); export default (WrappedComponent) => { return class extends Component { constructor(props) { super(props) this.state = { codeBtnText: '发送验证码' } this.getCode = this.getCode.bind(this) this.postVcode = this.postVcode.bind(this) } componentWillMount() { } getCode(mobile) { if (mobile === '') { this.setState({ tipsText: '请输入手机号码' }) this.refs.confirm.show() return } if (!/1[3|4|5|7|8]\d{9}/.test(mobile)) { this.setState({ tipsText: '请输入正确手机号码' }) this.refs.confirm.show() return } this.codeBtnDisable = true // console.log(this.codeBtnDisable) this.postVcode(mobile) let total = 59 this.setState({codeBtnText: `${total}秒`}) // this.codeBtnText = `${total}秒` this.timer = setInterval(() => { // console.log(total) --total // this.codeBtnText = `${total}秒` this.setState({codeBtnText: `${total}秒`}) if (total <= 0) { clearInterval(this.timer) // this.codeBtnText = '发送验证码' this.setState({codeBtnText: `发送验证码`}) this.codeBtnDisable = false } }, 1000) } postVcode(mobile) { var _params = { Phone: mobile } var that = this axios({ method: 'post', url: url + 'ComService/PostVcode', data: _params }) .then(function (res) { if (res.data.issuccess) { that.setState({ tipsText: res.data.message }) that.refs.confirm.show() //that.saveUserApplyStepList(res.data.result) } else { that.setState({ tipsText: res.data.message }) that.refs.confirm.show() that.codeBtnDisable = false clearInterval(that.timer) // that.codeBtnText = `发送验证码` this.setState({codeBtnText: `发送验证码`}) return false } }) .catch(function (error) { console.log(error) }) } render() { return ( <div> <WrappedComponent getCode={this.getCode} state={this.state} {...this.props}/> </div> ) } } }
register.js
import React, {Component} from 'react' import axios from 'common/js/http' import { url } from 'common/js/config' import Confirm from 'base/confirm/confirm' import { withRouter } from 'react-router-dom' import { setToken } from 'common/js/cache' import getCodeHOC from 'common/js/HOC' @getCodeHOC class Register extends Component{ constructor() { super() this.state = { mobile: '', password: '', tipsText: '', isOpen: false, inputType: 'password', codeBtnText: '发送验证码' } this.confirm = React.createRef() this.buttonBtn = React.createRef() this.handleMobileChange = this.handleMobileChange.bind(this) this.handlePassWordChange = this.handlePassWordChange.bind(this) this.handleLogin = this.handleLogin.bind(this) this.switchEye = this.switchEye.bind(this) this.goToLogin = this.goToLogin.bind(this) // this.getCode = this.getCode.bind(this) this.btnDisable = false this.codeBtnDisable = false // this.codeBtnText = '发送验证码' this.timer = null } componentDidMount() { let _mobile = localStorage.getItem('mobile') this.setState({ mobile: _mobile }) } handleMobileChange (e) { this.setState({ mobile: e.target.value }) } handleLogin (e) { let that = this let params = { Identifier:this.state.mobile, Credential:this.state.password } if (params.Identifier === '') { this.setState({ tipsText:'请输入手机号码' }) this.refs.confirm.show() return } if (!/1[3|4|5|7|8]\d{9}/.test(params.Identifier)) { this.setState({ tipsText:'请输入正确手机号码' }) this.refs.confirm.show() return } if (params.Credential === '') { this.setState({ tipsText:'请输入密码' }) this.refs.confirm.show() return false } axios({ method: 'post', url: url + 'Login/UserLogin', data: params }).then((res) => { // console.log(res); if (res.data.issuccess) { console.log(that.props); window.location.href = '/home' setToken(res.data.result.Token) localStorage.setItem('mobile', that.state.mobile) } else { that.setState({ tipsText: res.data.message }) that.refs.confirm.show() } }) } handlePassWordChange(e) { this.setState({ password: e.target.value }) } switchEye () { this.setState(prevState => ({ isOpen: !prevState.isOpen }), ()=> { this.state.isOpen ? this.setState({inputType: 'text'}) : this.setState({inputType: 'password'}) }) } shouldComponentUpdate(nextProps, nextState) { // console.log('nextProps', nextProps); console.log('nextState', nextState); if (nextState.mobile && (/1[3|4|5|7|8]\d{9}/.test(nextState.mobile)) && nextState.password ) { this.btnDisable = true } else { this.btnDisable = false } if (nextState.codeBtnText === '发送验证码') { this.codeBtnDisable = false } return true } goToLogin () { console.log(this.props); this.props.history.push('/login') } render() { return ( <div> <div className="title">用户注册</div> <div className="inputBox padType"> <div className="input size-0 align-1"> <label >手机号</label> <input type="tel" placeholder="请输入手机号" maxLength="11" value={this.state.mobile} onChange={this.handleMobileChange} /> </div> </div> <div className="inputBox padType"> <div className="input size-0 align-1"> <label >验证码</label> <input placeholder="请输入密码" maxLength="6" type="number"/> <div className={"send-smg-code " + (this.codeBtnDisable ? 'disable' : '')} onClick={()=>this.props.getCode(this.state.mobile)}>{this.props.state.codeBtnText}</div> </div> </div> <div className="inputBox padType"> <div className="input size-0 align-1"> <label >密 码</label> <input placeholder="请输入密码" maxLength="16" type={this.state.inputType} onChange={this.handlePassWordChange}/> <div className="eye" onClick={this.switchEye}> </div> </div> </div> <div className="agree-register"> <div className="agree-check"></div> <div className="agree-text"> 同意《 <a href="#/useAgreementRegister"> 注册协议 </a> 》 </div> </div> <div className="buttonBox disable"> <div className={"button " + (this.btnDisable ? '' : 'disable')}> 注册 </div> </div> <div className="child-mt20"> <div className="buttonBox reverse"> <div className="button reverse" onClick={this.goToLogin}> 已有账号,去登录 </div> </div> </div> <Confirm text={this.state.tipsText} confirmType='2' ref="confirm"></Confirm> </div> ) } } export default withRouter(Register)
forgetpassword.js
import React, {Component} from 'react' import axios from 'common/js/http' import { url } from 'common/js/config' import Confirm from 'base/confirm/confirm' import { withRouter } from 'react-router-dom' import { setToken } from 'common/js/cache' import HOC from 'common/js/HOC' // @HOC class Forgetpassword extends Component{ constructor() { super() this.state = { mobile: '', password: '', tipsText: '', isOpen: false, inputType: 'password', codeBtnText: '发送验证码' } this.confirm = React.createRef() this.buttonBtn = React.createRef() this.handleMobileChange = this.handleMobileChange.bind(this) this.handlePassWordChange = this.handlePassWordChange.bind(this) this.handleLogin = this.handleLogin.bind(this) this.switchEye = this.switchEye.bind(this) // this.getCode = this.getCode.bind(this) this.btnDisable = false this.codeBtnDisable = false // this.codeBtnText = '发送验证码' this.timer = null } componentDidMount() { let _mobile = localStorage.getItem('mobile') this.setState({ mobile: _mobile }) } handleMobileChange (e) { this.setState({ mobile: e.target.value }) } handleLogin (e) { let that = this let params = { Identifier:this.state.mobile, Credential:this.state.password } if (params.Identifier === '') { this.setState({ tipsText:'请输入手机号码' }) this.refs.confirm.show() return } if (!/1[3|4|5|7|8]\d{9}/.test(params.Identifier)) { this.setState({ tipsText:'请输入正确手机号码' }) this.refs.confirm.show() return } if (params.Credential === '') { this.setState({ tipsText:'请输入密码' }) this.refs.confirm.show() return false } axios({ method: 'post', url: url + 'Login/UserLogin', data: params }).then((res) => { // console.log(res); if (res.data.issuccess) { console.log(that.props); // window.location.href = '/home' let _href = window.location.href let _hrefArr = _href.split('#') window.location.href = _hrefArr[0] + '#/home'; //太low了。。。。 setToken(res.data.result.Token) localStorage.setItem('mobile', that.state.mobile) } else { that.setState({ tipsText: res.data.message }) that.refs.confirm.show() } }) } handlePassWordChange(e) { this.setState({ password: e.target.value }) } switchEye () { this.setState(prevState => ({ isOpen: !prevState.isOpen }), ()=> { this.state.isOpen ? this.setState({inputType: 'text'}) : this.setState({inputType: 'password'}) }) } shouldComponentUpdate(nextProps, nextState) { // console.log('nextProps', nextProps); console.log('nextState', nextState); if (nextState.mobile && (/1[3|4|5|7|8]\d{9}/.test(nextState.mobile)) && nextState.password ) { this.btnDisable = true } else { this.btnDisable = false } if (nextState.codeBtnText === '发送验证码') { this.codeBtnDisable = false } return true } render() { return ( <div> <div className="title">忘记密码</div> <div className="inputBox padType"> <div className="input size-0 align-1"> <label >手机号</label> <input type="tel" placeholder="请输入手机号" maxLength="11" value={this.state.mobile} onChange={this.handleMobileChange}/> </div> </div> <div className="inputBox padType"> <div className="input size-0 align-1"> <label >验证码</label> <input placeholder="请输入密码" maxLength="6" type="number"/> <div className={'send-smg-code ' + (this.codeBtnDisable ? 'disable' : '')} onClick={(e) => this.props.getCode(this.state.mobile)}>{this.props.state.codeBtnText}</div> </div> </div> <div className="inputBox padType"> <div className="input size-0 align-1"> <label >新密码</label> <input placeholder="请输入密码" maxLength="16" type={this.state.inputType} onChange={this.handlePassWordChange}/> <div className={ 'eye ' + (this.state.isOpen ? 'open' : '')} onClick={this.switchEye}></div> </div> </div> <div className="buttonBox "> <div className={'button ' + (this.btnDisable ? '': "disable")} ref={this.buttonBtn} onClick={this.handleLogin}> 确定 </div> </div> <Confirm text={this.state.tipsText} confirmType='2' ref="confirm"></Confirm> </div> ) } } export default withRouter(HOC(Forgetpassword))
4.注意点
一、使用装饰器语法需要安装transform-decorators-legacy插件并配置package
1.npm install babel-plugin-transform-decorators-legacy --save-dev
2.配置package中babel下plugin
"babel": { "presets": [ "react-app" ], "plugins": ["transform-decorators-legacy"] },
二、高阶组件中的复用方法或状态属性需要在其他组件中使用记得作为属性传递出去,以便其他组件使用