用react的思惟考慮網頁用戶登錄的邏輯

Lots of people use React as the V in MVC. Since React makes no assumptions about the rest of your technology stack, it's easy to try it out on a small feature in an existing project.css

    我大體意譯一下:React僅僅嘗試解決關於UI的某一個方面(不是所有)的問題,它不來假設你使用了什麼其它技術。它易於理解,能夠在您已經存在的項目中嘗試使用。背後的哲學是:我只作一件事(關於UI),而且把它作到極致。html

    這不是一篇叫你如何使用React的文章。它只是用react的方式思考一個問題,把它表達出來,若是您是業內人士,必定會用本身的技術棧和它做出對比。若是你這樣作了,這篇文章的目的就達到了。react

   這是一個登錄頁面,服務器一端提供restful形式的響應,這是一個單頁面程序。服務器響應的數據結構以下,| 表示可能性:
json

{
    state: ANONYMOUS | REMEMBER_ME | FULL,
    showCaptcha: true | false,
    message: WRONG_JSON_MESSAGE | USERNAME_PASSWORD_NOT_MATCH | UNKNOWN | SHOW_CAPTCHA | WRONG_CAPTCHA | NO_MESSAGE,
    user: null | {email: xxx@yyy},
    wtg: where to go
}

  客戶端rest請求的表:瀏覽器

路徑 http方法 content-type 響應
/login GET * 登錄頁面HTML(靜態)
/login POST application/json 上面提到的數據結構
/loginstatus GET * 上面提到的數據結構

 可能的用戶操做流程:服務器

  1. 用戶訪問/login,返回登錄html頁面。頁面內的rest客戶端訪問/loginstatus,獲取數據。restful

  2. 用戶輸入用戶名密碼等,rest客戶端post到服務器,獲取數據數據結構

  3. 用戶可能中途刷新了瀏覽器,那麼就和1同樣了。app

不論是哪一種可能,咱們都會獲取一個數據。數據有許多不一樣的組合,咱們把不一樣的組合叫作狀態,react的核心就是狀態(數據)和UI之間創建單向的聯繫。
工具

下面來分析一下可能的狀態:

一、用戶打開登錄頁面,此時經過/loginstatus獲取的數據多是:

{state: ANONYMOUS, message: NO_MESSAGE, showCaptcha: false}

這種狀態下,顯示,用戶名框,密碼框,登錄按鈕

二、用戶登陸時返回錯誤,此時的數據多是:

{state: ANONYMOUS, message: USERNAME_PASSWORD_NOT_MATCH, showCaptcha: false}

這時能夠文本框添加顯示錯誤狀態的css等。

三、用戶嘗試了好幾回,超過顯示驗證碼的閾值

{state: ANONYMOUS, message: USERNAME_PASSWORD_NOT_MATCH, showCaptcha: true}

此時開始,驗證碼字段顯示。爲何說此時開始呢?即便你刷新了瀏覽器,仍是會顯示驗證碼字段。

四、用戶登陸成功:

state: FULL, message: NO_MESSAGE, showCaptcha: false, wtg: "http://哪裏跌倒,哪裏起來"}

此時客戶端根據狀況開始新的頁面。

從整個過程來講,用react提倡的狀態來思考,一切行爲都通用化,沒有什麼特殊性。UI只是忠實的反應狀態而已,至因而顯示驗證碼,或提示用戶名錯誤都一視同仁。

代碼:

一、表單容器組件,主要是爲登錄表單增長一些效果切換,好比頁面初始打開時顯示的是Loading,而後在請求登錄狀態的時候顯示"querying state",最後根據query結果,顯示登錄表單。

var LoginFormContainer = React.createClass({
  getInitialState: function() {
    return {queryLoginState: true};
  },
  componentDidMount: function() {
    console.log(this.props.ucRestClient ? "ucrestclient is set." : "no ucrestclient");
    var that = this,
        restClient = this.props.ucRestClient;

    restClient.loginstate().then(function(response){
      console.log('response: ', response);
      that.setState({queryLoginState: false, entity: response.entity});
    });
  },
  render: function() {
    var c;
    if (this.state.queryLoginState) {
      c = <p>queryLoginState....</p>;
    } else {
      c = <LoginForm {...this.props} {...this.state.entity}/>;
    }
    return (
      <div className="login-form-container">
        {c}
      </div>
    );
  }
});

二、表單組件:

var UserNameField = React.createClass({
  componentDidMount: function() {
    console.log(this.props.value); // => true
  },
  render: function() {
    return (
      <div className="pure-control-group">
          <label htmlFor="username">Username</label>
          <input name="username" value={this.props.value} type="text" placeholder="Username"/>
      </div>);
  }
});

var PasswordField = React.createClass({
  render: function() {
    return (
      <div className="pure-control-group">
          <label htmlFor="password">Password</label>
          <input name="password" value={this.props.value} type="password" placeholder="Password"/>
      </div>);
  }
});

var CaptchaField = React.createClass({
  render: function() {
    return (
      <div className="pure-control-group">
          <label htmlFor="captcha">Captcha</label>
          <input name="captcha" value={this.props.value} placeholder="Captcha"/>
      </div>);
  }
});

var LoginForm = React.createClass({
  getInitialState: function() {
    return {};
  },
  handleSubmit: function(e) {
    e.preventDefault();
    if (this.state.submiting) {
      return;
    }

    var username = this.state.username,
        password = this.state.password,
        captcha = this.state.captcha,
        ucClient = this.props.ucRestClient,
        that = this;

    var canSubmit = true;
    if (!username || username.length < 3) {
      canSubmit = false;
    }

    if (!password || password.length < 6) {
      canSubmit = false;
    }

    if (this.state.showCaptcha) {
      if (!captcha || captcha.length !== 5) {
        canSubmit = false;
      }
    }

    if (canSubmit) {
      this.setState({submiting: true});
      ucClient.login({
       username: username,
       password: password,
       captcha: captcha
       }).then(function(response) {
	    		console.log('response: ', response);
          that.setState({submiting: false});
			});
    }
  },
  handleChange: function(e) {
    // DOMEventTarget, id, tagName
    var stateo = {};
    stateo[e.target.name] = event.target.value.trim();
    this.setState(stateo);
    // console.log(e.target.value);
  },
  render: function() {
    var captchaField;
    if (this.state.showCaptcha) {
      captchaField = <CaptchaField value={this.state.captcha} />;
    }
    return (
        <form className="pure-form pure-form-aligned" action="/login" method="POST" onSubmit={this.handleSubmit} onChange={this.handleChange}>
            <fieldset>
              <UserNameField value={this.state.username} />
              <PasswordField value={this.state.password} />
              {captchaField}
              <div className="pure-controls">
                    <label htmlFor="cb" className="pure-checkbox">
                        <input id="cb" type="checkbox"/> I've read the terms and conditions
                    </label>
                    <button type="submit" className="pure-button pure-button-primary">Submit</button>
                </div>
            </fieldset>
        </form>
    );
  }
});

三、rest客戶端工具代碼:

'use strict';

var rest, mime, csrf, client;

rest = require('rest');
mime = require('rest/interceptor/mime');
csrf = require('rest/interceptor/csrf');

var _csrf = window.jQuery("meta[name='_csrf']").attr("content"),
  _csrf_header = window.jQuery("meta[name='_csrf_header']").attr("content"),
	ucclient = rest.wrap(mime, {mime: 'application/json'}).wrap(csrf, {token: _csrf});

module.exports = {
	login: function(entity) {
		return ucclient({
			path: '/login',
			method: "POST",
			entity: entity});
	},
	loginstate: function() {
		return ucclient({
       path: '/loginstate',
       method: "GET"
     });
	}
};

 

  注意:以上代碼是本人在2天時間內(包括尋找開發環境的設置)經過閱讀reactjs官方文檔寫做而成,可能會存在很是規的代碼寫法,請指正。

   結論:以reactjs編寫UI界面,邏輯很是簡單明瞭,便於維護,強烈推薦嘗試。

相關文章
相關標籤/搜索