react+redux实战(二)----搭建express并将应用连接到数据库mongodb

上一篇文章:
react+redux实战(一)----基本流程

主要完成了基本页面的搭建,但是对于数据的交互还并不支持,因此为了构建一个完整的数据流,开始尝试将应用连接到数据库。

数据库选型(可以略过)

选型最基本的要求就是可用js操作。在选型阶段发现了wilddog(野狗),以简单的实时通信著称。

野狗确实特别合适flux,flux是为了给react或者其他前端框架做全局数据同步用的,野狗做的事情恰好就是各个客户端和服务器的数据同步,试想一下,我在手机上点了一个赞,更新了本地数据,然后本地数据自动同步了线上数据,线上数据又自动同步了你手机上的数据,然后state的改变触发重绘,在你的界面上弹出一个小红点。而这一系列的数据比对,传递,同步,重绘都是野狗和框架自动完成的。(摘自知乎)

而且它是也是js操作,使用事件方式来对数据库进行操作,而且数据库是以后台云方式存在的,如果只是构建react的完整数据流,完全可以不用后台,只搭配野狗就实现。我又没用野狗,还说这么多是想表达什么呢?感慨这实在是简单,用过的朋友希望能介绍下经验,后边有机会想尝试一把敏捷开发。

言归正传。

目前前端的主流方法还是利用ajax或者fetch这种方式向指定api请求数据,然后router处理请求返回数据,如果使用野狗提供的方法,可以将这一步和对数据库的读写操作综合为一步。确实高效快捷,然而这次本着学习的目的,想一探web应用的整个流程,还是选择走主流,所以这次选择使用mongodb,然后使用express作为后台。

将webpack-dev-server集成到整个web应用

既然选定后台使用express作为自己的web服务器,那么第一步就需要将webpack dev server集成进来,否则就不能使用webpack提供的模块实时打包和热加载功能。最简单的方式如下:

就是在入口html文件载入打包的js文件时指定完整的url地址,如

<script src="http://127.0.0.1:3000/assets/bundle.js"></script>

告诉页面应该去开发服务器地址获得脚本资源文件。使用过程中发现,bundle.js文件是webpack会打包生成出来的,如果应用中就只有这个一个输出,没有chunks的话,这样集成是可以的。但是要知道 webpack dev server 把编译后的静态文件是保存在内存里的,如果使用按需加载,就会找不到这些chunkfiles,抽取的公共文件也会找不到,所以我们不得不继续前行。

express本身就是一系列middleware的集合,而webpack-dev-server就是一个小型的express服务器,它就是用的webpack-dev-middleware来处理webpack编译后的输出,所以,我们在express中使用webpack的开发工具:webpack-dev-middlewarewebpack-hot-middleware。webpack-hot-middleware是结合webpack-dev-middleware使用的,用来实现热更新。

使用前记得安装。dev模式下,webpack的配置如下,只需注意注释地方(其它地方不用关注):

'use strict';
let path = require('path');
let webpack = require('webpack');
let baseConfig = require('./base');
let defaultSettings = require('./defaults');

// Add needed plugins here,reload为true意思是,如果遇到不能hot load 的情况,就整页刷新
var hotMiddlewareScript = 'webpack-hot-middleware/client?reload=true';
let config = Object.assign({}, baseConfig, {
  entry: [
    './src/index',
   //入口文件修改,原来对应webpack-dev-server的是
  //'webpack-dev-server/client?http://0.0.0.0:8000', 
  //'webpack/hot/only-dev-server',改为如下:
    hotMiddlewareScript
  ],
  cache: true,
  devtool: 'eval-source-map',
  plugins: [
    //添加下面3个插件,这个原来应该也有,如果没有就加上
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin()
  ],
  module: defaultSettings.getDefaultModules()
});

config.module.loaders.push({
  test: /\\.(js|jsx)$/,
  loader: 'react-hot!babel-loader',
  include: [].concat(
    config.additionalPaths,
    [ path.join(__dirname, '/../src') ]
  )
});

module.exports = config;

note:就只有注释的几个地方需要注意修改,webpack原来如何配置的,其它地方维持不变就行。

接下来在express的启动文件中配置(为方便,贴出完整代码,关于配置主要是if判断中的语句):

var express=require('express');

var routes=require('./routes/index');
var app=express();

//nodeJs模板语言,选用ejs(需要安装),如下配置可正常使用.html文件作为入口
app.engine('.html', require('ejs').__express);
//change the template main catelog
app.set('views',__dirname+'/src');
app.set('view engine','html')

var isDev = process.env.NODE_ENV !== 'production';

if(isDev){
    const webpack = require('webpack');
    const webpackDevMiddleware = require('webpack-dev-middleware');
    const webpackHotMiddleware = require('webpack-hot-middleware');
    const config = require('./webpack.config');

    const compiler=webpack(config);

    app.use(webpackDevMiddleware(compiler,{
        publicPath:config.output.publicPath,
        noInfo:true,
        stats:{
            colors:true
        }
    }));
    app.use(webpackHotMiddleware(compiler))
      //设置静态资源地址
    app.use(express.static(__dirname+'/public'));

    app.use('/',routes);

    app.listen(3000,function(){
        console.log("runing")
    })
}

note:两个middleware应在routes之前配置。
至此,webpack-dev-server整合到了nodeJs后台。

使用mongodb数据库

mongodb我们都听过,但是使用时,我们安装和使用的是mongoose,这是一个提供了和mongodb相映射的nodeJs库,它可以将数据库中的数据类型转换为js对象供我们在应用中使用。安装mongoose(npm install mongoose)之前要首先安装好mongodb(brew install mongodb)。

向express启动文件中添加

var mongoose=require('mongoose');
//导入定义的模型
global.dbHandle=require('./models/haddledb.js');
//连接数据库,默认端口号是27017,mediumReact是自己的数据库名称
global.db=mongoose.connect('mongodb://localhost:27017/mediumReact');

models/haddledb.js文件中是定义好的模型

var mongoose=require('mongoose');
var Schema=mongoose.Schema;
//定义一个Schema
var ArticlesSchema=new Schema({
    id:{type:Number},
    title:{type:String},
    genre:{type:Number},
    source:{type:String},
    praise_count:{type:Number},
    comment_count:{type:Number},
    publish_time:{type:Date},
    banner_pic:{type:String}
});
//定义一个model
var ArticlesModel=mongoose.model("Articles",ArticlesSchema);

主要就是理解Schema定义了文档的结构,是数据库的骨架,不具备操作数据库的能力;Model是由Schema生成的模型,具备操作数据库能力;Entity是Model生成的实体,其操作也能影响数据库。一般我们都是操作model。

那么现在的当务之急,就是向数据库中添加一些数据,mongoose提供的CRUD方法也很简洁:

//可以使用model创建一个实体
ArticlesEntity=new ArticlesModel({
    "id": 2001,
    "title": "生活不是等待暴风雨过去而是让我们学会在雨中翩翩起舞,生活不是等待暴风雨过去而是让我们学会在雨中翩翩起舞。",
    "genre": 1,
    "source": "片刻",
    "praise_count": 234,
    "comment_count": 65,
    "publish_time": "2016-08-10 14:08:36 +0800",
    "banner_pic": "/images/grid-article-banner.jpg"
});
//然后保存到数据库
ArticlesEntity.save();

但是,对于我们初来乍到的人来说,最好的还是可视化工具,我使用的是Robomongo,稍微看两下其菜单,就能知道如何操作了。

建立路由api,完善请求流程

新闻列表页请求数据的antion:

import fetch from 'isomorphic-fetch'
import { createActions } from 'redux-actions';

export const { fetchArticles } = createActions({
    FETCH_ARTICLES: async () => {
        try {
            //express后台中需要建立'/articles'路由,来处理请求数据
            let response = await fetch('/articles');
            let articles = await response.json();

            return {  articles }
        } catch (err) {
            console.log(err);
        }
    }
});

对应的reducer:

import { handleActions } from 'redux-actions';
import { FETCH_ARTICLES } from '../actions/index.js';

export default handleActions({
    FETCH_ARTICLES: (state, action) => {
        let payload = action.payload;

        return {...state,isFecting:false,articles:payload.articles}
    }
}, {});

express的routes文件:

var express=require('express');
var router=express.Router();
var mongoose=require('mongoose');
var articles=mongoose.model('Articles');

//get home page,因为使用了react-router来处理处理做单页应用,在express中我们就只用给其一个入口路径
router.get('/',function(req,res,next){
    res.render('index',{title:"medium-react"});
});
//列表页get数据的请求地址
router.get('/articles',function(req,res,next){
        //使用find()方法有点简单了,因为首页基本会涉及分页,这个以后再改进
    articles.find({},function(err,results){
        if(err){
            console.log('error message',err);
            return;
        }
        res.json(results);
    })
});
module.exports=router;

这个routes文件是在express的启动文件中使用的:

var routes=require('./routes/index');
app.use('/',routes);

写在最后

至此,整个web应用就已经搭建完成,这一章让我体验了一把完整的web应用的基本流程,感觉不错。但是遗留问题也还很多,比如连接数据库的初衷,就是更好的观察、处理异步交互,然而在文章详情页,整个结构树太深

用工具画图好累,就手绘凑合看吧。。

目前只在文章详情页connect到数据库,也就意味着dispatch方法是在这个容器中获取的,但是对于评论中的点赞事件可能发生在主回复Comment组件中,也可能是从回复Reply组件中,如果将dispatch 方法一层层传递下去,不仅路径深,而且中间都不曾用到该方法。或许也可以这样:点赞之后将数据传递(比如观察者模式)到container ,然后dispatch这个请求。你还有什么好的方法么?

下一节先实现最基础的异步交互:

react+redux实战(三)----异步交互

【主要参考资源】
Express结合Webpack的全栈自动刷新
express使用指南
Mongoose学习参考文档

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容