React+Node初嘗試


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

項目代碼在:GitHub/lilu_movie , 歡迎大家關注或提問題。

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

 

安裝:

首先安裝express框架;

npm install express --save

生成文件后,可以通過npm start啟動應用。

注意:ejs 從3.x后不支持layout,可以通過express-partials ,但是不支持4,4之后用include

緊接着我迫不及待安裝material-ui:

npm install material-ui --save

然后出現錯誤:

所以必須安裝react依賴:

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM