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>硅 谷 直 聘</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)}}>密 码:</InputItem>
<WhiteSpace/>
<Button type='primary' onClick={this.login}>登 陆</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)))