註冊邏輯完善以及個人中心頁面完成
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 user
model中加入註冊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啥都想搞