第十一步:添加Character的組件

2021-10-23 14:32 更新

第十一步:添加Character的組件

這個組件包含一個簡單的表單。成功或失敗的消息會顯示在輸入框下的help-block里。

組件

在app/components目錄新建文件AddCharacter.js

import React from 'react';
import AddCharacterStore from '../stores/AddCharacterStore';
import AddCharacterActions from '../actions/AddCharacterActions';

class AddCharacter extends React.Component {
  constructor(props) {
    super(props);
    this.state = AddCharacterStore.getState();
    this.onChange = this.onChange.bind(this);
  }

  componentDidMount() {
    AddCharacterStore.listen(this.onChange);
  }

  componentWillUnmount() {
    AddCharacterStore.unlisten(this.onChange);
  }

  onChange(state) {
    this.setState(state);
  }

  handleSubmit(event) {
    event.preventDefault();

    var name = this.state.name.trim();
    var gender = this.state.gender;

    if (!name) {
      AddCharacterActions.invalidName();
      this.refs.nameTextField.getDOMNode().focus();
    }

    if (!gender) {
      AddCharacterActions.invalidGender();
    }

    if (name && gender) {
      AddCharacterActions.addCharacter(name, gender);
    }
  }

  render() {
    return (
      <div className='container'>
        <div className='row flipInX animated'>
          <div className='col-sm-8'>
            <div className='panel panel-default'>
              <div className='panel-heading'>Add Character</div>
              <div className='panel-body'>
                <form onSubmit={this.handleSubmit.bind(this)}>
                  <div className={'form-group ' + this.state.nameValidationState}>
                    <label className='control-label'>Character Name</label>
                    <input type='text' className='form-control' ref='nameTextField' value={this.state.name}
                           onChange={AddCharacterActions.updateName} autoFocus/>
                    <span className='help-block'>{this.state.helpBlock}</span>
                  </div>
                  <div className={'form-group ' + this.state.genderValidationState}>
                    <div className='radio radio-inline'>
                      <input type='radio' name='gender' id='female' value='Female' checked={this.state.gender === 'Female'}
                             onChange={AddCharacterActions.updateGender}/>
                      <label htmlFor='female'>Female</label>
                    </div>
                    <div className='radio radio-inline'>
                      <input type='radio' name='gender' id='male' value='Male' checked={this.state.gender === 'Male'}
                             onChange={AddCharacterActions.updateGender}/>
                      <label htmlFor='male'>Male</label>
                    </div>
                  </div>
                  <button type='submit' className='btn btn-primary'>Submit</button>
                </form>
              </div>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

export default AddCharacter;

現(xiàn)在你可以看到這些組件的一些共同點:

  1. 設(shè)置組件的初始狀態(tài)為store中的值。
  2. componentDidMount中添加store監(jiān)聽者,在componentWillUnmount中移除。
  3. 添加onChange方法,無論何時當(dāng)store改變后更新組件狀態(tài)。

handleSubmit方法的作用和你想的一樣——處理添加新角色的表單提交。當(dāng)它為真時我們能在addCharacter action里完成表單驗證,不過這樣做的話,需要我們將輸入?yún)^(qū)的DOM節(jié)點傳到action,因為當(dāng)nameTextField無效時,需要focus在輸入框,這樣用戶可以直接輸入而無需點擊一下輸入框。

Actions

在app/actions目錄新建AddCharacterActions.js

import alt from '../alt';

class AddCharacterActions {
  constructor() {
    this.generateActions(
      'addCharacterSuccess',
      'addCharacterFail',
      'updateName',
      'updateGender',
      'invalidName',
      'invalidGender'
    );
  }

  addCharacter(name, gender) {
    $.ajax({
      type: 'POST',
      url: '/api/characters',
      data: { name: name, gender: gender }
    })
      .done((data) => {
        this.actions.addCharacterSuccess(data.message);
      })
      .fail((jqXhr) => {
        this.actions.addCharacterFail(jqXhr.responseJSON.message);
      });
  }
}

export default alt.createActions(AddCharacterActions);

當(dāng)角色被成功加入數(shù)據(jù)庫后觸發(fā)addCharacterSuccess,當(dāng)失敗時觸發(fā)addCharacterFail,失敗的原因可能是無效的名字,或角色已經(jīng)在數(shù)據(jù)庫中存在了。當(dāng)角色的Name字段和Gender單選框改變時由onChange觸發(fā)updateNameupdateGender,同樣的,當(dāng)輸入的名字無效或沒有選擇性別時觸發(fā)invalidNameinvalidGender。

Store

在app/stores目錄新建AddCharacterStore.js

import alt from '../alt';
import AddCharacterActions from '../actions/AddCharacterActions';

class AddCharacterStore {
  constructor() {
    this.bindActions(AddCharacterActions);
    this.name = '';
    this.gender = '';
    this.helpBlock = '';
    this.nameValidationState = '';
    this.genderValidationState = '';
  }

  onAddCharacterSuccess(successMessage) {
    this.nameValidationState = 'has-success';
    this.helpBlock = successMessage;
  }

  onAddCharacterFail(errorMessage) {
    this.nameValidationState = 'has-error';
    this.helpBlock = errorMessage;
  }

  onUpdateName(event) {
    this.name = event.target.value;
    this.nameValidationState = '';
    this.helpBlock = '';
  }

  onUpdateGender(event) {
    this.gender = event.target.value;
    this.genderValidationState = '';
  }

  onInvalidName() {
    this.nameValidationState = 'has-error';
    this.helpBlock = 'Please enter a character name.';
  }

  onInvalidGender() {
    this.genderValidationState = 'has-error';
  }
}

export default alt.createStore(AddCharacterStore);

nameValidationStategenderValidationState指向Bootstrap提供的代表驗證狀態(tài)的表單控件。

helpBlock是在輸入框下顯示的狀態(tài)信息,如“Character has been added successfully”。

onInvalidName方法當(dāng)Character Name字段為空時觸發(fā)。如果name在EVE中不存在,將由onAddCharacterFail輸出另一個錯誤信息。

最后,打開routes.js并添加新的路由/add,以及AddCharacter組件方法:

import React from 'react';
import {Route} from 'react-router';
import App from './components/App';
import Home from './components/Home';
import AddCharacter from './components/AddCharacter';

export default (
  <Route handler={App}>
    <Route path='/' handler={Home} />
    <Route path='/add' handler={AddCharacter} />
  </Route>
);

這里簡單總結(jié)了從你輸入角色名稱開始的整個流程:

  1. 觸發(fā)updateName action,傳遞event對象。
  2. 調(diào)用onUpdateName store處理程序。
  3. 使用新的名稱更新狀態(tài)。

在下一節(jié),我們將實現(xiàn)添加和保存新character到數(shù)據(jù)庫的后端代碼。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號