React 同構

React 同構

搬運
http://www.javashuo.com/article/p-mxfmiscw-cc.htmljavascript

究竟什麼是同構呢?

同構就是但願前端 後端都使用同一套邏輯 同一套代碼
Nodejs出現後 這一設計方式的實現更加容易了 後端一樣能夠根據路徑來加載js文件渲染指定的頁面 而React又擁有renderToString 以及 renderToStaticMarkup方法
能夠將react組建渲染成html字串html

renderToString VS renderToStaticMarkup
這二者都是將 React元素變成原始的HTML, 且都是服務端在使用, 不一樣的是renderToStaticMarkup不會建立出額外的React的屬性 好比 data-react-id等 主要是用於建立一個純粹的靜態頁, 這樣能夠節省不少帶寬前端

實現一個最簡單的同構

就是但願服務器在響應某個請求所調用的邏輯
客戶端對於該路徑的處理也是使用同一套邏輯 (客戶端對於路徑處理 指的是運用了Hash或者Histroy State的SPA頁面 對不一樣路徑的處理)
更通俗一點的說法, 客戶端和服務端對於同一個路徑所做出的響應會使用到共同的文件(但並不表示對於同一個路徑 他們處理的邏輯徹底相同)java

關於react-router的browserHistroynode

若是你設置某個頁面的router爲 / 的話
訪問這個頁面的路徑應該是 domian.xx:port/
以前沒有理解browserHistroy 目標app是在一個很深的路徑下
當時使用這個路徑去訪問
localhost/ReactStudy/RouterStudy/
天然就會出現 Location / Not matchreact

Server端

咱們知道Server端對於一個請求的處理, 就是根據不一樣的路徑作出不一樣的響應 因此Server端的響應應該是一個完整的頁面 以後在頁面上發生的任何路徑的改變, 都應該交給react route處理 Server再也不參與後續的任務webpack

這裏Server使用koa來實現 服務端的路徑處理使用koa-routerweb

let app = koa();
  let router = koaRouter();
  router.get(['/', '/home'], function*() {

    // 執行view插件
    // 調用render方法  this是app的context
    // 因此調用的this.render 也就是
    this.body = this.render('Home', {
      microdata: microdata,
      mydata: {
        nick: 'server render body'
      }
    },1);
  });
  app.use(router.routes()).use(router.allowedMethods());

能夠看到整個響應體this.body的渲染由一個render方法完成
這個render調用了一個文件專門渲染服務端的頁面 這個頁面請求一個js文件 這個js文件就是整個客戶端的邏輯segmentfault

可能這個頁面的一些渲染就是由和客戶端通的組件獲得的 可是並不必定會有共同的部分
這樣服務器能夠直接將一些信息渲染到頁面中 解決了SEO的問題
可是這個過程很是的慢後端

慢的緣由是由於這個render須要根據路徑動態的require一些組件 而後解析等等
這些被require的組件若是是採用了ES6的方式編寫 須要用 'babel-register' 來處理
它是一個Hook, 能夠在require一個組件的時候作一些處理, 將ES6編譯成ES5
因爲這裏是動態的處理這個編譯的過程 這個服務端的響應就更加慢了

render() {
    // 對象的解構賦值
    const { microdata, title, children } = this.props;
    return (
      <html>
        <head>
          <meta charSet='utf-8' />
          <meta httpEquiv='X-UA-Compatible' content='IE=edge' />
          <meta httpEquiv='Cache-Control' content='no-siteapp' />
          <meta name='renderer' content='webkit' />
          <meta name='keywords' content='demo' />
          <meta name='description' content='demo' />
          <meta name='viewport' content='width=device-width, initial-scale=1' />
          <title>{title}</title>
        </head>
        <body>
          {children}
          {this.renderScripts()}
        </body>
      </html>
    );
  }

須要注意的是, 並非有了babel-loader 全部的ES6均可以順利的變成ES5, Babel Online上能夠看到關於ES6的語法有不一樣的presets的設置 默認狀況下 class 的static 不能直接經過babel-loader編譯 解決方案在這裏http://jsrocks.org/2016/01/configuring-babel-6-for-node-js/
須要參數 你能夠在.babelrc中加入下面的配置或者在webpack.config.js中添加params參數

{
 "plugins": ["es2015", "stage-0"]
}

客戶端

客戶端最終的結果是一個OR多個js文件, 它包含了全部的頁面上的邏輯以及頁面之間的跳轉(這裏用的是react-router)
服務端生成了頁面以後, 能夠將一些參數(好比路徑的參數) 直接寫在頁面中, 而後客戶端從頁面中獲取這些參數值而後執行,

客戶端主要邏輯

render() {
    let { isServer, mydata } = this.props;
    return (
      <Router history={browserHistory}>
        <Route path="/" component={Nav}>
          <Route path="/device/:deviceID" component={DeviceView}/>
        </Route>
      </Router>
    );
  }

等客戶端的邏輯一開始執行 就會根據當前的url作匹配 執行特定的組件邏輯

相關文章
相關標籤/搜索