文章30 | 阅读 13737 | 点赞0
对于一门语言的学习,少不了动手练习,今天我们就尝试一下,如何用React编写一个简单的程序,实现功能包括网络请求数据,绑定数据进行增删改查,并进行相应的路由操作。
下面我们来年代码:
我们创建一个package.json, 里面包含一些开发库还有核心库:
{
"name": "demo4",
"version": "1.0.0",
"description": "",
"scripts": {
"start": "webpack-dev-server --progress --colors --hot --inline -d",
"build": "webpack --progress --colors --minify"
},
"license": "ISC",
"dependencies": {
"classnames": "2.1.2",
"react": "0.13.3",
"react-router": "^2.5.1"
},
"devDependencies": {
"babel-core": "5.6.18",
"babel-eslint": "^5.0.4",
"babel-loader": "5.1.4",
"node-args": "1.0.2",
"node-libs-browser": "^1.0.0",
"raw-loader": "0.5.1",
"eslint": "^1.10.3",
"eslint-config-rackt": "^1.1.1",
"eslint-plugin-react": "^3.16.1",
"style-loader": "0.12.3",
"todomvc-app-css": "2.0.1",
"webpack": "1.9.11",
"webpack-dev-server": "1.11.0"
}
}
react 和react-router是我们一定要添加的核心库,react-router是路由功能的核心库,如果我们要进行页面跳转,一定要用到。
还有一些开发库,比如webpack, 用于打包工作,babel用于我们要把ES6代码转化,webpack-dev-server主要负责本地测试服务器功能,可以把我们的测试部署到上面,配置hot-reload进行实时刷新工作。
对于这个package.json,我们配置好以后,可以执行npm install进行全部安装。
然后我们在看一下webpack.config.js的编写:
var path = require('path');
var webpack = require('webpack');
var env = process.env.NODE_ENV;
var config = {
entry: ['./app'],
output: {
path: path.join(__dirname, 'dist'),
publicPath: '/dist/',
filename: 'bundle.js'
},
plugins: [],
module: {
loaders: [{
test: /\.js$/,
exclude: /node_modules/,
include: __dirname,
loader: 'babel'
}, {
test: /\.css?$/,
loaders: ['style', 'raw'],
include: __dirname
}]
}
};
config.plugins = config.plugins.concat(
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
new webpack.optimize.OccurenceOrderPlugin());
module.exports = config;
其中主要的功能是entry 和output, 我们要定义个程序的如果,方便webpack进行代码打包工作,这个我们的如果是app.js, 在制定一个输入路径,这里我们引用了node的path库,以便于指定当前文件路径。
在配置一个loader,进行代码转化工作:
loaders: [{
test: /\.js$/,
exclude: /node_modules/,
include: __dirname,
loader: 'babel'
},
我们接下来创建一个Store用于数据管理, 比如从网络获取数据,用户交互过程中,数据更换等等操作, 我们看一下代码:
const API = 'http://addressbook-api.herokuapp.com/contacts';
let _contacts = []
let _initCalled = false
let _changeListeners = []
const ContactStore = {
init: function () {
if (_initCalled)
return
_initCalled = true
getJSON(API, (err, res) => {
res.contacts.forEach(contact => {
_contacts[contact.id] = contact;
})
ContactStore.notifyChange();
})
},
addContact: function (contact, cb) {
postJSON(API, { contact: contact}, res => {
_contacts[res.contact.id] = res.contact
ContactStore.notifyChange()
if (cb) cb(res.contact)
})
},
removeContact: function (id, cb) {
deleteJSON(API + '/' +id, cb)
delete _contacts[id]
ContactStore.notifyChange()
},
getContacts: function () {
const array = []
for (const id in _contacts)
array.push(_contacts[id])
return array;
},
getContact: function(id) {
return _contacts[id]
},
notifyChange: function() {
_changeListeners.forEach(listener => {
listener()
})
},
addChangeListener: function (listener) {
_changeListeners.push(listener)
},
removeChangeListener: function(listener) {
_changeListeners = _changeListeners.filter(l => {
return listener !== l
})
}
}
localStorage.token = localStorage.token || (Date.now() * Math.random())
function getJSON(url, cb) {
const req = new XMLHttpRequest()
req.onload = function () {
if (req.status === 404) {
cb(new Error('not found'))
} else {
cb(null, JSON.parse(req.response))
}
}
req.open('GET', url)
req.setRequestHeader('authorization', localStorage.token)
req.send()
}
function postJSON(url, obj, cb) {
const req = new XMLHttpRequest()
req.onload = () => {
cb(JSON.parse(req.response))
}
req.open('POST', url)
req.setRequestHeader('Content-Type', 'application/json;charset=UTF-8')
req.setRequestHeader('authorization', localStorage.token)
req.send(JSON.stringify(obj))
}
function deleteJSON(url, cb) {
const req = new XMLHttpRequest()
req.onload = cb
req.open('DELETE', url)
req.setRequestHeader('authorization', localStorage.token)
req.send()
}
export default ContactStore
以上语法用ES6编写,主要实现功能是对数据进行增删改查的操作,并把数据提交到后台服务器。数据请求用到XMLHttpRequest,是javascript最原始的ajax方案,但是对于es6做了很大改进,个人很喜欢。
最后我们编写一个主入口文件app.js, 我们要在这个文件中创建几个组件比如App, 整个应用的root组件,还有contact组件,用于显示联系人信息, 还有newcontact组件,用于创建一个联系人, 空组件,用于显示无信息状态,最后是一个首页显示组件。
在这个文件中,我们还要创建一个router,用来处理页面的跳转操作。
我们看一下代码:
import React from 'react';
import {
browserHistory, Router, Route, IndexRoute, Link, withRouter
} from 'react-router';
import ContactStore from './ContactStore';
import './app.css';
const App = React.createClass({
getInitialState() {
return {
contacts: ContactStore.getContacts(),
loading: true
};
},
componentWillMount() {
ContactStore.init();
},
componentDidMount() {
ContactStore.addChangeListener(this.updateContacts);
},
componentWillUnmount() {
ContactStore.removeChangeListener(this.updateContacts);
},
updateContacts() {
if(!this.isMounted())
return
this.setState({
contacts: ContactStore.getContacts(),
loading: false
})
},
render() {
const contacts = this.state.contacts.map(contact => {
return <li key={contact.id}><Link to={`/contact/${contact.id}`}>{contact.first}</Link></li>;
});
return (
<div className="App">
<div className="ContactList">
<Link to="/contact/new">New Contact</Link>
<ul>
{contacts}
</ul>
</div>
<div className="Content">
{this.props.children}
</div>
</div>
);
}
});
const Index = React.createClass({
render(){
return <h1>Address Book</h1>
}
});
const Contact = withRouter(
React.createClass({
getStateFromStore(props){
const {id} = props? props.params: this.props.params
return {
contact: ContactStore.getContact(id)
};
},
getInitialState() {
return this.getStateFromStore();
},
componnentDidMount() {
ContactStore.addChangeListener(this.updateContact);
},
componentWillUnmount() {
ContactStore.removeChangeListener(this.updateContact);
},
componentWillReceiveProps(nextProps) {
this.setState(this.getStateFromStore(nextProps));
},
updateContact() {
if(!this.isMounted) {
return;
}
this.setState(this.getStateFromStore);
},
destory() {
const {id} = this.props.params;
ContactStore.removeContact(id);
this.props.router.push('/');
},
render() {
const contact = this.state.contact || {};
const name = contact.first + '' + contact.last;
const avatar = contact.avatar || 'http://placecage.com/50/50';
return (
<div className="Contact">
<img height="50" src={avatar} key={avatar} />
<h3>{name}</h3>
<button onClick={this.destory}>Delete</button>
</div>
);
}
})
);
const NewContact = withRouter(
React.createClass({
createContact(event) {
event.preventDefault();
ContactStore.addContact({
first: React.findDOMNode(this.refs.first).value,
last: React.findDOMNode(this.refs.last).value
}, (contact) => {
this.props.router.push(`/contact/${contact.id}`);
});
},
render() {
return (
<form onSubmit={this.createContact}>
<p>
<input type="text" ref="first" placeholder="First name"/>
<input type="text" ref="last" placeholder="Last name"/>
</p>
<p>
<button type="submit">Save</button> <Link to="/">Cancel</Link>
</p>
</form>
);
}
})
);
const NotFound = React.createClass({
render(){
return <h2>Not Found</h2>
},
})
React.render((
<Router history={browserHistory}>
<Route path="/" component={App}>
<IndexRoute component={Index} />
<Route path="contact/new" component={NewContact} />
<Route path="contact/:id" component={Contact} />
<Route path="*" component={NotFound} />
</Route>
</Router>
), document.getElementById('example'))
对于这个Demo, 没有做更详细的解释,相应大家这个阶段,对react已经有了初步了解,如果还是不理解,可以参考之前的教程。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/jiangbo_phd/article/details/51768976
内容来源于网络,如有侵权,请联系作者删除!