一个react项目案例02 注册和登陆实现原理分析

1.登陆组件
在这里插入图片描述

/*
登陆的路由组件
 */

import React, {Component} from 'react'
import {
  NavBar,
  WingBlank,
  List,
  InputItem,
  WhiteSpace,
  Button
} from 'antd-mobile'
import {connect} from 'react-redux'
import {Redirect} from 'react-router-dom'

import {login} from '../../redux/actions'

import Logo from '../../components/logo/logo'

const ListItem = List.Item

class Login extends Component {
  state = {
    username: '',  // 用户名
    password: '',  // 密码
  }

  login = () => {
    this.props.login(this.state)
  }

  // 处理输入数据的改变: 更新对应的状态
  handleChange = (name, val) => {
    // 更新状态
    this.setState({
      [name]: val  // 属性名不是name, 而是name变量的值
    })
  }

  toRegister = () => {
    this.props.history.replace('/register')
  }

  render() {

    const {msg, redirectTo} = this.props.user
    // 如果redirectTo有值, 就需要重定向到指定的路由
    if(redirectTo) {
      return <Redirect to={redirectTo}/>
    }

    return (
      <div>
        <NavBar>&nbsp;&nbsp;&nbsp;</NavBar>
        <Logo/>
        <WingBlank>
          <List>
            {msg ? <div className='error-msg'>{msg}</div> : null}
            <WhiteSpace/>
            <InputItem placeholder='请输入用户名' onChange={val => {this.handleChange('username', val)}}>用户名:</InputItem>
            <WhiteSpace/>
            <InputItem placeholder='请输入密码' type="password" onChange={val => {this.handleChange('password', val)}}>&nbsp;&nbsp;&nbsp;:</InputItem>
            <WhiteSpace/>

            <Button type='primary' onClick={this.login}>&nbsp;&nbsp;&nbsp;</Button>
            <WhiteSpace/>
            <Button onClick={this.toRegister}>还没有账户</Button>
          </List>
        </WingBlank>
      </div>
    )
  }
}

export default connect(
  state => ({user: state.user}),
  {login}
)(Login)

UI组件不能跟redux进行交互,所以需要将UI组件用connect包装生成容器组件,传一个函数进去。我隐约知道其中的原理了,login会引起state的变化,而react会因为state的变化而重新渲染。那么state是如何作为属性传递到Register组件的呢?注意观察入口函数,store会作为Provider的标签的属性传递下去。而store里面保存了所有组件要用到的数据。那么问题又来了这个sore是怎么来的?
看下这个函数,表示看不懂了。但可以知道store是是根据reducer来产生的。reducer又是怎么来的呢,reducer是根据state和action加工而来的。到这里大概可以理清楚整个流程了。

export interface StoreCreator {
  <S>(reducer: Reducer<S>, enhancer?: StoreEnhancer<S>): Store<S>;
  <S>(reducer: Reducer<S>, preloadedState: S, enhancer?: StoreEnhancer<S>): Store<S>;
}

表单接收到用户名和密码,onChange函数监听到表单数据变化会调用
handleChange函数,来设置state状态。onClick监听到按钮点击会调用login,login是一个action动作。在reducer中,action会引起state的改变产生一个reducer,这个机制是怎么实现的?action和state是怎么传递进去的?reducer生成后,进而产生新的store,store里面包含了user对象,render之前,选取出user对象,根据条件觉得渲染跳转,若登陆成功则跳转到主页面或者完善信息页面,否则提示错误信息。
在这里插入图片描述

{"code":0,"data":{"_id":"6050995bfed9952358b0e5d8",
"username":"dashen4",
"type":"dashen",
"info":"精通 前端",
"post":"前端工程师",
"header":"头像1"}}

2.action-types.js

/*
包含n个action type名称常量
 */
export const AUTH_SUCCESS = 'auth_success' // 注册/登陆成功
export const ERROR_MSG = 'error_msg' // 错误提示信息   请求前/请求后

3.antion.js

/*
包含n个action creator
异步action
同步action
 */
import io from 'socket.io-client'
import {
  AUTH_SUCCESS,
  ERROR_MSG
} from './action-types'
import {
  reqRegister,
  reqLogin
} from '../api'



// 授权成功的同步action
const authSuccess = (user) => ({type: AUTH_SUCCESS, data: user})
// 错误提示信息的同步action
const errorMsg = (msg) => ({type: ERROR_MSG, data: msg})


// 注册异步action
export const register = (user) => {
  const {username, password, password2, type} = user
  // 做表单的前台检查, 如果不通过, 返回一个errorMsg的同步action
  if(!username) {
    return errorMsg('用户名必须指定!')
  } else if(password!==password2) {
    return errorMsg('2次密码要一致!')
  }
  // 表单数据合法, 返回一个发ajax请求的异步action函数
  return async dispatch => {


    // 发送注册的异步ajax请求
    /*const promise = reqRegister(user)
    promise.then(response => {
      const result = response.data  // {code: 0/1, data: user, msg: ''}
    })*/
    const response = await reqRegister({username, password, type})
    const result = response.data //  {code: 0/1, data: user, msg: ''}
    if(result.code===0) {// 成功
      getMsgList(dispatch, result.data._id)
      // 分发授权成功的同步action
      dispatch(authSuccess(result.data))
    } else { // 失败
      // 分发错误提示信息的同步action
      dispatch(errorMsg(result.msg))
    }
  }
}

// 登陆异步action
export const login = (user) => {

  const {username, password} = user
  // 做表单的前台检查, 如果不通过, 返回一个errorMsg的同步action
  if(!username) {
    return errorMsg('用户名必须指定!')
  } else if(!password) {
    return errorMsg('密码必须指定!')
  }

  return async dispatch => {
    // 发送注册的异步ajax请求
    /*const promise = reqLogin(user)
    promise.then(response => {
      const result = response.data  // {code: 0/1, data: user, msg: ''}
    })*/
    const response = await reqLogin(user)
    const result = response.data
    if(result.code===0) {// 成功
      getMsgList(dispatch, result.data._id)
      // 分发授权成功的同步action
      dispatch(authSuccess(result.data))
    } else { // 失败
      // 分发错误提示信息的同步action
      dispatch(errorMsg(result.msg))
    }
  }
}

4.reducers.js

/*
包含n个reducer函数: 根据老的state和指定的action返回一个新的state
 */
import {combineReducers} from 'redux'

import {
  AUTH_SUCCESS,
  ERROR_MSG,
  RECEIVE_USER,
  RESET_USER,
  RECEIVE_USER_LIST,
  RECEIVE_MSG_LIST,
  RECEIVE_MSG,
  MSG_READ
} from './action-types'

import {getRedirectTo} from '../utils'

const initUser = {
  username: '', // 用户名
  type: '', // 用户类型 dashen/laoban
  msg: '', // 错误提示信息
  redirectTo: '' // 需要自动重定向的路由路径
}
// 产生user状态的reducer
function user(state=initUser, action) {
  switch (action.type) {
    case AUTH_SUCCESS: // data是user
      const {type, header} = action.data
      return {...action.data, redirectTo: getRedirectTo(type, header)}
    case ERROR_MSG: // data是msg
      return {...state, msg: action.data}
    case RECEIVE_USER: // data是user
      return action.data
    case RESET_USER: // data是msg
      return {...initUser, msg: action.data}
    default:
      return state
  }
}

}

export default combineReducers({
  user
})
// 向外暴露的状态的结构: {user: {}}

5.store.js

/*
redux最核心的管理对象模块
 */
import {createStore, applyMiddleware} from 'redux'
import thunk from 'redux-thunk'
import {composeWithDevTools} from 'redux-devtools-extension'

import reducers from './reducers'

// 向外暴露store对象
export default createStore(reducers, composeWithDevTools(applyMiddleware(thunk)))
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值