Flux in reactjs with CRUD Example (Part-2)
Tiếp tục part 1 part 2 này chúng ta sẽ làm tiếp các phần như là:
1. List (Danh sách các user đã đang ký)
2. edit thông tin user
3. delete user
4. sử dụng router
Bây giờ chúng ta sẽ làm phần List trước nhé.
Tại thư mục components các bạn tạo 1 component với tên là ListUserComponent tương tự như CreateUserComponents
import React from 'react';
import CreateUser from './CreateUserComponent.jsx'
import userAction from '../actions/UserActions.jsx';
import UserStore from '../stores/UserStore.jsx';
export default class ListUserComponent extends React.Component {
constructor() {
super();
this.state = this._getState();
this._onChange = this._onChange.bind(this);
}
_getState() {
return {
users: UserStore.getUserList()
};
}
_onChange(){
this.setState(this._getState());
}
componentDidMount() {
UserStore.addChangeListener(this._onChange);
}
componentWillUnmount() {
UserStore.removeChangeListener(this._onChange);
}
render() {
return (
<section id="ListUserComponent">
<div className="container-fluid">
<div className="row">
<div className="col-md-1">Id</div>
<div className="col-md-2">Name</div>
<div className="col-md-2">sex</div>
</div>
{this.createTableRow}
</div>
<CreateUser/>
</section>
)
}
get createTableRow(){
var rows = [];
var users = this.state.users;
Object.keys(users).forEach(function (key) {
console.log(key);
rows.push(
<div key={key} className="row">
<div className="col-md-1">{key}</div>
<div className="col-md-2">{users[key].name}</div>
<div className="col-md-2"> {users[key].sex}</div>
</div>)
});
return rows;
}
}
Như các bạn thấy ở trên component này vẫn sẽ “nghe ngóng” từ UserStore. Khi có event change sẽ lập tức gọi hành động _onChange() để lấy lại giá trị stage.
Trong đoạn code này bạn còn thấy chúng ta sẽ sử dụng form tạo mới user để ngay dưới list các user vừa tạo. Việc này thực hiện rất đơn giản vì chúng ta đã có sẵn CreateUserComponent rồi, khi muốn sủ dụng ta chỉ cần khai báo là được.
Chúng ta cũng thay đổi file app.jsx một chút
import React from "react";
import ReactDOM from "react-dom";
import ListUser from "./components/ListUserComponent.jsx";
ReactDOM.render(<ListUser/>, document.getElementById('body'));
Thay vì sử dụng CreateUserComponent như bài trước, bài nay chúng ta dùng ListUserComponent.
Build lại hệ thống và chạy lại xem nào.
Bây giờ cữ mỗi lần add thêm 1 user thì lập tức danh sách user cũng đã được thay đổi theo rồi.
Tiếp theo là hành động delete. Với hành động này chúng ta cần làm nhưng việc sau:
1. Them button delete. => cần sửa ở ListUserComponet
2. Click button gửi action delete => cần đăng ký them event delete ở action
3. Xóa user, gửi action xóa thành công => cần sử lại store
Sau khi sửa xong chúng ta sẽ được như sau
1, ListUserComponet
import React from 'react';
import CreateUser from './CreateUserComponent.jsx'
import userAction from '../actions/UserActions.jsx';
import UserStore from '../stores/UserStore.jsx';
export default class ListUserComponent extends React.Component {
constructor() {
super();
this.state = this._getState();
this._onChange = this._onChange.bind(this);
}
_getState() {
console.log("get list user");
console.log(UserStore.getUserList());
return {
users: UserStore.getUserList()
};
}
_onChange() {
this.setState(this._getState());
}
componentDidMount() {
UserStore.addChangeListener(this._onChange);
}
componentWillUnmount() {
UserStore.removeChangeListener(this._onChange);
}
render() {
return (
<section id="ListUserComponent">
<div className="container-fluid">
<div className="row">
<div className="col-md-1">Id</div>
<div className="col-md-2">Name</div>
<div className="col-md-2">sex</div>
<div className="col-md-2">Action</div>
</div>
{this.createTableRow}
</div>
<CreateUser/>
</section>
)
}
deleteUser() {
userAction.delete(this);
}
get createTableRow(){
var rows = [];
var users = this.state.users;
var deleteUser = this.deleteUser;
Object.keys(users).forEach(function (key) {
console.log(key);
rows.push(
<div key={key} className="row">
<div className="col-md-1">{key}</div>
<div className="col-md-2">{users[key].name}</div>
<div className="col-md-2"> {users[key].sex}</div>
<div className="col-md-2"> <button onClick={deleteUser.bind(key)}> Delete</button></div>
</div>)
});
return rows;
}
}
2, UserAction
import Dispatcher from '../dispatcher/Dispatcher.jsx'
export default {
create: (user) => {
console.log("create user");
Dispatcher.dispatch({
actionType: 'CREATE_USER',
user: user
});
},
delete: (key) => {
console.log("delete user" + key);
Dispatcher.dispatch({
actionType: 'DELETE_USER',
deleteUserKey: key
});
}
}
3, UserStore
import BaseStore from './BaseStore.jsx'
class UserStore extends BaseStore{
constructor() {
super();
this.userIndex = 0;
this.listData = {};
this.subscribe(() => this.handler.bind(this));
}
/**
* Register callback to handle all updates
*
* @param {Object} action
*/
handler(action) {
switch (action.actionType) {
case 'CREATE_USER':
this.listData[this.userIndex] = action.user;
this.userIndex = this.userIndex + 1;
console.log(this.listData);
this.emitChange();
break;
case 'DELETE_USER':
delete this.listData[action.deleteUserKey];
this.emitChange();
break;
default :
}
}
getUserList() {
return this.listData
}
}
const userStore = new UserStore();
export default userStore;
ở đây chúng ta đã đăng ký thêm một hành động là ‘DELETE_USER’. Cứ mỗi khi phát hiện ra event này thì UserStore sẽ xóa đi 1 user trong biến listData với key đã được truyền vào.
Build và thử lại trên màn hình nhé. Sau khi click nút delete user sẽ được xóa luôn khỏi list trên màn hình.
như vậy phần delete đã xong bây giời chúng ta sẽ làm tiếp phần edit. Để áp dụng đươc phần router chúng ta sẽ làm trang edit riêng nhé.
Ở đây các bạn có thể thấy rằng chúng ta sẽ sử dụng thêm thư viên react-router.
Đầu tiên để setup router ta sửa lại file app.jsx như sau:
import React from "react";
import ReactDOM from "react-dom";
import {Router, Route, Redirect} from "react-router";
import createBrowserHistory from "history/lib/createBrowserHistory";
import EditUser from "./components/EditUserComponent.jsx";
import ListUser from "./components/ListUserComponent.jsx";
let history = createBrowserHistory();
var routes = (
<Route >
<Redirect from="/" to="/user"/>
<Route path="user" component={ListUser}/>
<Route path="user/:id/edit" component={EditUser}/>
</Route>
);
ReactDOM.render(<Router history={history}>{routes}</Router>, document.getElementById('body'));
EditUserComponent.jsx
import React from 'react';
import linkedState from 'react-link';
import {Link} from 'react-router'
import userAction from '../actions/UserActions.jsx';
import UserStore from '../stores/UserStore.jsx';
export default class EditUserComponent extends React.Component {
constructor() {
super();
this.state = {};
this._onChange = this._onChange.bind(this);
}
_getState() {
var id = this.props.params.id;
var user = UserStore.getUserById(id);
user.id = id;
return user
}
_onChange() {
this.setState(this._getState());
}
componentDidMount() {
this._onChange();
var id = this.props.params.id;
UserStore.isViewed(id);
UserStore.addChangeListener(this._onChange);
}
componentWillUnmount() {
UserStore.removeChangeListener(this._onChange);
}
render() {
return (
<section id="CreateUserComponent">
<div>
ID: {this.state.id}
</div>
<div>
Name:<input type="text" name="name" valueLink={linkedState(this, 'name')}/><br/>
</div>
<div>
Sex:<select valueLink={linkedState(this, 'sex')} >
<option type="radio" name="gender" value="male" > Male </option>
<option type="radio" name="gender" value="female" > Female </option>
<option type="radio" name="gender" value="other" > Other </option>
</select>
</div>
<div>
<button type="submit" onClick={this.editUser.bind(this)}>Save</button>
</div>
{this.state.isUpdateSuccess == true ?
<Link to="/user">edit success back to Home</Link> : ""
}
</section>
)
}
editUser() {
userAction.edit(this.state)
}
}
để lấy được param truyền vào từ router ta sử dụng dòng lệnh sau: this.props.params.id;
Bây giờ là action. Ta sẽ đăng ký thêm một action edit nữa
import Dispatcher from '../dispatcher/Dispatcher.jsx'
export default {
create: (user) => {
console.log("create user");
Dispatcher.dispatch({
actionType: 'CREATE_USER',
user: user
});
},
edit: (user) => {
console.log("edit user" + user.id);
Dispatcher.dispatch({
actionType: 'EDIT_USER',
user: user
});
},
delete: (key) => {
console.log("delete user" + key);
Dispatcher.dispatch({
actionType: 'DELETE_USER',
deleteUserKey: key
});
}
}
UserStore cũng sửa 1 ít
/**
* Created by thangkc on 14/12/2015.
*/
import BaseStore from './BaseStore.jsx'
class UserStore extends BaseStore{
constructor() {
super();
this.userIndex = 0;
this.listData = {};
this.subscribe(() => this.handler.bind(this));
}
/**
* Register callback to handle all updates
*
* @param {Object} action
*/
handler(action) {
switch (action.actionType) {
case 'CREATE_USER':
this.listData[this.userIndex] = action.user;
this.userIndex = this.userIndex + 1;
console.log(this.listData);
this.emitChange();
break;
case 'DELETE_USER':
delete this.listData[action.deleteUserKey];
this.emitChange();
break;
case 'EDIT_USER':
var editedUser = action.user;
editedUser.isUpdateSuccess = true;
this.listData[action.user.id] = editedUser;
this.emitChange();
break;
default :
}
}
getUserList() {
return this.listData
}
getUserById(id){
return this.listData[id] || {}
}
isViewed(id){
this.listData[id].isUpdateSuccess = false;
}
}
const userStore = new UserStore();
export default userStore;
Ok thế là xong rồi. Bây giờ build lại và và chạy xem nào.
Lỗi đúng không? Bởi vì việc dùng router nên chúng ta sẽ không thể view trước tiếp từ file html nữa. bạn hãy chạy dòng lệnh
npm run start
rồi sau đó vào localhost:3000 nhé.
Tới đây thì mọi chuyện ổn rồi. Sau khi click vào button edit chúng ta sẽ sang được trang edit và tất cả các thông tin của user sẽ được hiện ra đầy đủ. Bạn thử edit rồi quay về trang home xem kết quả nhé. Mọi nội dung chúng ta edit đểu đã được apply.
Tới đây chúng ta đã kết thúc chuỗi bài viết CRUD sử dung react js va flux. Hẹn gặp lại các bạn vào các bài viết khác.