這個組件包含一個簡單的表單。成功或失敗的消息會顯示在輸入框下的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)在你可以看到這些組件的一些共同點:
componentDidMount
中添加store監(jiān)聽者,在componentWillUnmount
中移除。onChange
方法,無論何時當(dāng)store改變后更新組件狀態(tài)。handleSubmit
方法的作用和你想的一樣——處理添加新角色的表單提交。當(dāng)它為真時我們能在addCharacter
action里完成表單驗證,不過這樣做的話,需要我們將輸入?yún)^(qū)的DOM節(jié)點傳到action,因為當(dāng)nameTextField
無效時,需要focus在輸入框,這樣用戶可以直接輸入而無需點擊一下輸入框。
在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ā)updateName
和updateGender
,同樣的,當(dāng)輸入的名字無效或沒有選擇性別時觸發(fā)invalidName
和invalidGender
。
在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);
nameValidationState
和genderValidationState
指向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é)了從你輸入角色名稱開始的整個流程:
updateName
action,傳遞event對象。onUpdateName
store處理程序。在下一節(jié),我們將實現(xiàn)添加和保存新character到數(shù)據(jù)庫的后端代碼。
更多建議: