React+Node初嘗試

這是第一次寫React和Node,選用的是前端Material-ui框架,後端使用的是Express框架,數據庫採用的是Mongodb。css

項目代碼在:GitHub/lilu_movie , 歡迎你們關注或提問題。html

這是一個經過從電影天堂抓取數據並顯示的電影網站,demo部署在heroku上面。前端

 

安裝:node

首先安裝express框架;react

npm install express --save

生成文件後,能夠經過npm start啓動應用。webpack

注意:ejs 從3.x後不支持layout,能夠經過express-partials ,可是不支持4,4以後用includegit

緊接着我火燒眉毛安裝material-ui:es6

npm install material-ui --save

而後出現錯誤:github

因此必須安裝react依賴:web

npm install react@^15.0.0 --save

npm install react-dom@^15.0.0 --save

npm install react-tap-event-plugin@^1.0.0 --save 

安裝nodemon

nodemon ./bin/www #更改會自動重啓服務

本地安裝數據庫mongodb

而後npm安裝操做mongodb的mongoose 

npm install mongoose

npm install express-mongoose 

接着你會發現按照material-ui的import引入報錯,

使用es6查看系統支持哪些es6語法

npm install es6-checker

由於react使用es6和jsx語法,因此須要轉化,安裝以下包:

複製代碼
npm install babel-loader babel-core babel-preset-es2015 —save-dev

npm install jsx-loader —save-dev

npm install babel-preset-react

 

複製代碼

安裝webpack

複製代碼
npm install webpack —save-dev


npm install css-loader —save-dev


npm install webpack-dev-server —save-dev
複製代碼

這裏有必要提一下:-save-dev表明安裝的包適用於開發的,相似於rails中安裝Gem放在:development環境下,這樣生產環境就不會安裝。

而後在webpack配置文件中babels的loaders中query加入presets

 

由於須要一些css文件,react經過require style文件,須要安裝

npm install style-loader —save-dev

npm install css-loader —save-dev // 這個和style一塊兒用纔有效果

在webpack中的config 加上loader: "style-loader!css-loader」,就不用require使用style!css!了

 

 

啓動腳本: 

配置package.json文件,給script添加命令

  "start": ["node ./bin/www", "webpack」],

編寫webpack.config.js配置文件,更改html引入文件

在webpack-dev-server 沒有真正生成文件,還得要引入<script src=「localhost:8080/assets/bundle.js"></script>

運行npm run dev,看webpack-dev-server效果

 

Express後端流程改變: 

剛開始,我用一向的後臺思路經過routes渲染頁面,頁面html引入react的js文件,reactjs文件link後臺js響應;後臺相應經過鏈接mongodb獲取數據庫內容。

 

很成功,獲取到相應的內容了,可是由於使用react,因此很差每次都取加載一次內容,而後又不用引擎模板,這些數據如何放入state讓react用diff算法本身計算呢?怎樣變成單頁面應用呢?

 

而後我想到就是ajax;上網google一下,發現用fetch能實現像ajax那樣的請求。同一個component能夠很容易實現fetch數據改變this的state。

 

這時候發現不知道怎麼經過點擊標籤,渲染新頁面,

 

 

因爲react規定父元素只能改變子元素,可是很差將子元素改變父元素;

通常咱們都會把許多內容都搞到最頂級那個父元素的state,這樣其餘都有可能與他有關聯,而子元素改變父元素的state的方法就是經過回調setState;

因此這裏咱們能夠將movies放在最頂的component,而後點擊標籤,就去回調去改變這個父元素的state,用到這個state的子元素就會刷新。

 代碼詳見這個commit

可是這樣太hacky了,違背react理念,代碼難理解;

 

有沒有其餘更好的辦法呢?

 

Google查找答案發現有兩種方法:

 

  1.  使用react-router

  2.  若是不是用react-router,則得這樣寫https://github.com/ReactTraining/react-router/blob/master/docs/Introduction.md

 

react-route根據history傳入的連接,找到你對應routes的component,而後改變children,成功渲染改組件。

 

對於不一樣組件改變同個內容仍是使用react-router

 

使用react-router發現client端經過router的連接,局部更新內容;

這樣子說,徹底不須要server後臺每一個路由每次渲染不一樣頁面了,只須要server不一樣連接給出不一樣內容,而後渲染同一個頁面,這個頁面經過react-router去改變內容便可。

因此刪除後端全部router路由;

按照React Router官方教程實現相應代碼。

 

這時候發現一個問題:

渲染同一個頁面就要在後端引入前端的routes,也就須要到es6了,可是以前後端沒有經過webpack進行es6的轉化,因此還要對後端的入口文件進行webpack轉化。

 

對後端server.js進行webpack的bundle後,很容易報錯,首先要在web pack中排除掉node_module的文件,而後須要引入各類loader; 

server端要import client端的routes過來,可是route的component會引用相應的component。若是遇到client的內容,有些react-router/server是處理不了的,會報沒有window錯誤。

 如下是最終的webpack.server.config.js 

複製代碼
var webpack = require("webpack");
var fs = require("fs");
var path = require("path");

module.exports = {
  entry: [
    path.resolve(__dirname, 'server.js')
  ],

  output: {
    filename: 'server.bundle.js'
  },
  target: 'node',

  externals: fs.readdirSync(path.resolve(__dirname, 'node_modules')).concat([
    'react-dom/server', 'react/addons',
  ]).reduce(function (ext, mod) {
    ext[mod] = 'commonjs ' + mod
    return ext
  }, {}),

  node: {
    __filename: true,
    __dirname: true
  },
  module: {
    loaders: [
      {
        test: /\.css$/,
        loader: "style-loader!css-loader"
      }, {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: "babel",
        query: { presets: ['react', 'es2015'] }
      }, {
        test: /.json$/, loader: 'json-loader'
      }, {
        test: /.node$/, loader: 'node-loader'
      }]

  }
}
複製代碼

本文內容有待更新,具體代碼和問題詳見Github倉庫的commit

相關文章
相關標籤/搜索