ReactJS学习系列课程(React 整体流程使用案例)

x33g5p2x  于2022-03-06 转载在 其他  
字(7.7k)|赞(0)|评价(0)|浏览(397)

对于一门语言的学习,少不了动手练习,今天我们就尝试一下,如何用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://github.com/jiangbophd/React-Learning

相关文章