共计 8508 个字符,预计需要花费 22 分钟才能阅读完成。
注册逻辑完善以及个人中心页面完成
1 reg 组件验证逻辑
和 login 一样的 验证规则
import React , {Component}from ‘react’;
import PropTypes from ‘prop-types’;
import {connect} from ‘dva’;
import {Form, Icon, Input, Button, Checkbox,message} from ‘antd’;
import {routerRedux} from ‘dva/router’;
const backgroundImage = require(‘../assets/back.jpg’);
const FormItem = Form.Item;
class Reg extends Component{
handleSubmit = (e) => {
e.preventDefault();
const {dispatch} = this.props
this.props.form.validateFields((err, values) => {
if (!err) {
const {userName,password,againPwd} = values
if (password === againPwd) {
dispatch({type: ‘user/reg’, payload: { userName,password} })
} else {
message.warning(‘ 您两次输入的密码不一致 ’);
}
}
});
}
render() {
const {getFieldDecorator,getFieldError} = this.props.form
return (
<div style={styles.form}>
<h1> 注册 </h1>
<Form onSubmit={this.handleSubmit}>
<FormItem>
{getFieldDecorator(‘userName’, {
rules: [{required: true, message: ‘ 请输入用户名 ’},
{max:20,message: ‘ 最大长度不能超过 20’}],
})(
<Input prefix={<Icon type=”user” style={{ color: ‘rgba(0,0,0,.25)’ }} />} placeholder=” 用户名 ” />
)}
</FormItem>
<FormItem>
{getFieldDecorator(‘password’, {
rules: [{required: true, message: ‘ 请输入密码 ’},
{pattern:/^(?![^a-zA-Z]+$)(?!\D+$)/,message: ‘ 密码必须包含数字和字母 ’},
{min:6,message: ‘ 最小长度为 6 位 ’},
{max:12,message: ‘ 最大长度 12 位 ’},],
})(
<Input prefix={<Icon type=”lock” style={{ color: ‘rgba(0,0,0,.25)’ }} />} type=”password” placeholder=” 密码 ” />
)}
</FormItem>
<FormItem>
{getFieldDecorator(‘againPwd’, {
rules: [{required: true, message: ‘ 请输入确认密码 ’},
{pattern:/^(?![^a-zA-Z]+$)(?!\D+$)/,message: ‘ 密码必须包含数字和字母 ’},
{min:6,message: ‘ 最小长度为 6 位 ’},
{max:12,message: ‘ 最大长度 12 位 ’},],
})(
<Input prefix={<Icon type=”lock” style={{ color: ‘rgba(0,0,0,.25)’ }} />} type=”password” placeholder=” 再次输入密码 ” />
)}
</FormItem>
<FormItem>
<Button block type=”primary” onClick={this.handleSubmit}>
注册
</Button>
<a> 忘记密码 </a>
或 <a href=”#/login”> 登陆!</a>
</FormItem>
</Form>
</div>
)
}
componentWillMount () {
if(this.props.state.user.isLogin) {
this.props.dispatch(routerRedux.push(‘/’))
}
}
}
const styles = {
form: {
maxWidth: ‘400px’,
margin: ‘0 auto’,
paddingTop: ‘100px’,
}
};
Reg.propTypes = {
};
function mapStateToProps(state) {
return {
state
}
}
// export default ListData;
export default connect(mapStateToProps)(Form.create()(Reg));
2 userService 加入注册 api
有后台的话请换成自己的
export function regUser({userName,password}) {
return {
userName: `${userName}`,
password: `${password}`
};
}
3 usermodel 中加入注册 action
应为是注册,所以没有对 state 中的数据作处理。顺带把退出登陆 action 也做了
import * as userService from ‘../services/userService’;
import {routerRedux} from ‘dva/router’;
export default {
namespace: ‘user’,
state:{
isLogin:false,
user:{}
},
effects: {
*login({payload: { userName,password} }, {call, put}) {
const result = yield call(userService.getUser, { userName,password})
yield put({
type: ‘updateUser’,
payload: {
result
}
})
yield put(routerRedux.push(‘/’))
},
*reg({payload: { userName,password} }, {call, put}) {
const result = yield call(userService.regUser, { userName,password})
yield put(routerRedux.push(‘/login’))
},
*logOut({payload: {} },{call, put}){
yield put({type: ‘userOut’})
}
},
reducers: {
‘updateUser'(state, { payload: data}) {
let r = data.result
return {isLogin:true,user:r}
},
‘userOut'(state) {
return {isLogin:false,user:{}}
}
},
};
4 Person 组件创建,来展示个人中心的数据
import React , {Component}from ‘react’;
import {Card, Col, Row , Timeline, Icon} from ‘antd’;
import PropTypes from ‘prop-types’;
import {connect} from ‘dva’;
import ‘./my.css’;
class Person extends Component{
render() {
return (
<div style={{background: ‘#ECECEC’, padding: ’30px’}}>
<Row gutter={16}>
<Col span={8}>
<Card title=” 个人信息 ” bordered={false}>
<p> 性别:{this.props.state.user.user.sex}</p>
<p> 工作:{this.props.state.user.user.job}</p>
<p> 兴趣:{this.props.state.user.user.like}</p>
<p> 公司:{this.props.state.user.user.work}</p>
<p> 工作地址:{this.props.state.user.user.location}</p>
<p> 博客:{this.props.state.user.user.blog}</p>
<p> 简介:{this.props.state.user.user.desp}</p>
</Card>
</Col>
<Col span={8}>
<Card title=”dva 课程进度 ” bordered={false}>
<Timeline>
<Timeline.Item dot={<Icon type=”check-circle-o” style={{ fontSize: ’16px’}} />} color=”green”>1 dva 初始化工程,导航菜单 </Timeline.Item>
<Timeline.Item dot={<Icon type=”check-circle-o” style={{ fontSize: ’16px’}} />} color=”green”>2 列表数据渲染 </Timeline.Item>
<Timeline.Item dot={<Icon type=”check-circle-o” style={{ fontSize: ’16px’}} />} color=”green”>3 react-markdown 渲染详情页 </Timeline.Item>
<Timeline.Item dot={<Icon type=”check-circle-o” style={{ fontSize: ’16px’}} />} color=”green”>4 数据分类标签 </Timeline.Item>
<Timeline.Item dot={<Icon type=”check-circle-o” style={{ fontSize: ’16px’}} />} color=”green”>5 登陆注册等页面 </Timeline.Item>
<Timeline.Item dot={<Icon type=”check-circle-o” style={{ fontSize: ’16px’}} />} color=”green”>6 登陆逻辑以及路由权限 </Timeline.Item>
<Timeline.Item dot={<Icon type=”check-circle-o” style={{ fontSize: ’16px’}} />} color=”green”>7 注册逻辑 </Timeline.Item>
<Timeline.Item dot={<Icon type=”clock-circle-o” style={{ fontSize: ’16px’}} />} color=”red”>8 课程总结 </Timeline.Item>
</Timeline>
</Card>
</Col>
<Col span={8}>
<Card title=” 我的帖子 ” bordered={false}>
<p>1. 服务器迁移至 aws 日本机房 </p>
<p>2. 学好 java</p>
<p>3. 搞定 python</p>
<p>4. 上手 react</p>
<p>5. 人工智能发展 </p>
</Card>
</Col>
</Row>
</div>
)
}
componentWillMount () {
}
}
Person.propTypes = {
id: PropTypes.string.isRequired,
};
function mapStateToProps(state) {
return {
state
};
}
// export default ListData;
export default connect(mapStateToProps)(Person);
5 个人中心页面创建 MyPage
使用了 Person 组件
import React from ‘react’;
import {connect} from ‘dva’;
import Header from ‘../components/Header’;
import Person from ‘../components/Person’;
function MyPage() {
return (
<div>
<Header keys={[‘my’]}/>
<div style={{paddingTop:20,paddingLeft:100,paddingRight:100,paddingBottom:50}}>
<Person/>
</div>
</div>
);
}
MyPage.propTypes = {
};
export default connect()(MyPage);
6 个人中心需要加入权限判断
在路有中使用 AuthRouter
import React from ‘react’;
import {Router, Route, Switch} from ‘dva/router’;
import IndexPage from ‘./routes/IndexPage’;
import DetailPage from ‘./routes/DetailPage’;
import NewUserPage from ‘./routes/NewUserPage’;
import ApiPage from ‘./routes/ApiPage’;
import AboutPage from ‘./routes/AboutPage’;
import LoginPage from ‘./routes/LoginPage’;
import RegPage from ‘./routes/RegPage’;
import MyPage from ‘./routes/MyPage’;
import AuthRouter from ‘./components/AuthRouter’;
function RouterConfig({history}) {
return (
<Router history={history}>
<Switch>
<Route path=”/” exact component={IndexPage} />
<Route path=”/detail/:id” exact component={DetailPage} />
<Route path=”/into” exact component={NewUserPage} />
<Route path=’/about’ component={AboutPage}/>
<Route path=”/login” exact component={LoginPage} />
<Route path=”/reg” exact component={RegPage} />
<AuthRouter path=’/api’ component={ApiPage}></AuthRouter>
<AuthRouter path=’/my’ component={MyPage}></AuthRouter>
</Switch>
</Router>
);
}
export default RouterConfig;
7 修改 Header 组件,动态显示登陆,注册,个人中心,退出登陆
import React from ‘react’;
import {Menu, Icon, Input,Avatar} from ‘antd’;
import PropTypes from ‘prop-types’;
import {Link} from ‘dva/router’;
import {connect} from ‘dva’;
const Search = Input.Search;
const Header = ({dispatch,state,keys}) => {
const isLoged = state.user.isLogin
function MyHeader() {
function logOut(e){
e.preventDefault();
console.log(‘logout’);
dispatch({type: ‘user/logOut’,payload: {}})
}
if(isLoged){
return <Menu
selectedKeys={keys}
mode=”horizontal”
>
<Menu.Item key=”node” disabled>
<Icon type=”tag” />CNODE
</Menu.Item>
<Menu.Item key=”search”>
<Search placeholder=”input text search”
onSearch={v => console.log(v)}
enterButton/>
</Menu.Item>
<Menu.Item key=”index”>
<Link to=”/”><Icon type=”appstore” /> 首页 </Link>
</Menu.Item>
<Menu.Item key=”into”>
<Link to=”/into”><Icon type=”appstore” /> 新手入门 </Link>
</Menu.Item>
<Menu.Item key=”api”>
<Link to=”/api”><Icon type=”appstore” />API</Link>
</Menu.Item>
<Menu.Item key=”about”>
<Link to=”/about”><Icon type=”appstore” /> 关于 </Link>
</Menu.Item>
<Menu.Item key=”my”>
<Avatar src=”https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png” />
<span style={{fontSize:16}}><Link to=”/my”>{state.user.user.name}</Link></span>
</Menu.Item>
<Menu.Item key=”logout”>
<Icon type=”logout”/><span onClick={logOut}> 退出登陆 </span>
</Menu.Item>
</Menu>
}else{
return <Menu
selectedKeys={keys}
mode=”horizontal”
>
<Menu.Item key=”node” disabled>
<Icon type=”tag” />CNODE
</Menu.Item>
<Menu.Item key=”search”>
<Search placeholder=”input text search”
onSearch={v => console.log(v)}
enterButton/>
</Menu.Item>
<Menu.Item key=”index”>
<Link to=”/”><Icon type=”appstore” /> 首页 </Link>
</Menu.Item>
<Menu.Item key=”into”>
<Link to=”/into”><Icon type=”appstore” /> 新手入门 </Link>
</Menu.Item>
<Menu.Item key=”api”>
<Link to=”/api”><Icon type=”appstore” />API</Link>
</Menu.Item>
<Menu.Item key=”about”>
<Link to=”/about”><Icon type=”appstore” /> 关于 </Link>
</Menu.Item>
<Menu.Item key=”reg”>
<Link to=”/reg”><Icon type=”appstore” /> 注册 </Link>
</Menu.Item>
<Menu.Item key=”login”>
<Link to=”/login”><Icon type=”appstore” /> 登陆 </Link>
</Menu.Item>
</Menu>
}
}
return (
<MyHeader/>
)
}
Header.propTypes = {
keys: PropTypes.array.isRequired
};
function mapStateToProps(state) {
return {
state
}
}
// export default ListData;
export default connect(mapStateToProps)(Header);
好不容易坚持更完了 dva 的实战入门课程。cnode 的整个功能都已经实现,原网站是使用得 github 的授权登陆。本课程中是模拟了后台 api 来登陆注册,虽然是假数据,但是足够你明白前后的交互。下节课总结一下,为本次课程画上句号,希望对学习 react 的你有一定的帮助。
今天的课程就到这里了,别忘了关注我 mike 啥都想搞