对于一门语言的学习,少不了动手练习,今天我们就尝试一下,如何用React编写一个简单的程序,实现功能包括网络请求数据,绑定数据进行增删改查,并进行相应的路由操作。
下面我们来年代码:
package.json
我们创建一个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
然后我们在看一下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'
},
ConfigureStore.js
我们接下来创建一个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.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://www.f2er.com/react/306530.html