dva開發cnode網站(7)

註冊邏輯完善以及個人中心頁面完成

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啥都想搞
mike啥都想搞

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章