成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

koa 實(shí)現(xiàn) react-view 原理

zxhaaa / 2855人閱讀

摘要:今天,其實(shí)講的是在實(shí)現(xiàn)同構(gòu)過程中看到過,可能非常容易被忽視更小的一個(gè)點(diǎn)。每一個(gè)架構(gòu)的框架都會涉及到層的展現(xiàn),也不例外。這種說法即對也不對。總結(jié)其實(shí),實(shí)現(xiàn)非常簡單,我們也從一些維度看到了設(shè)計(jì)一個(gè)的一般方法。

在之前我們有過一篇『React 同構(gòu)實(shí)踐與思考』的專欄文章,給讀者實(shí)踐了用 React 怎么實(shí)現(xiàn)同構(gòu)。今天,其實(shí)講的是在實(shí)現(xiàn)同構(gòu)過程中看到過,可能非常容易被忽視更小的一個(gè)點(diǎn) —— React View。

React View

每一個(gè) BS 架構(gòu)的框架都會涉及到 View 層的展現(xiàn),Koa 也不例外。我們在做 View 層的時(shí)候有兩種做法,一種是做成插件形式,對于 View 來說就是模板引擎,另一種是做成中件間的形式。

再說到 React,常常有人說它是增強(qiáng)版的模板引擎。這種說法即對也不對。

從表象來看的確,React 可以替換變量,有條件判斷,有循環(huán)判斷,JSX 語法讓渲染過程和 HTML 沒什么兩樣,畢竟說到底 React 就是 JavaScript,而 React 所推崇的無狀態(tài)函數(shù),也徹徹底底把 React 變成了像是模板的樣子。

從內(nèi)在來看,React 它還是 JavaScript,它可以方便地做模塊化管理,有內(nèi)部狀態(tài),有自己的數(shù)據(jù)流。它可以做一部分 Controller,或者說,可以完全承擔(dān) Controller 的工作。

但是在服務(wù)端,我們需要模板是為了作 HTML 的同步請求,因此說地簡單一些就只需要渲染成 HTML 的功能就可以了。當(dāng)然,特殊的一點(diǎn)是,之所以讓 React 作模板就是可以讓服務(wù)端跑到客戶端的渲染邏輯,并解決單頁應(yīng)用常常詬病的加載后白屏的問題。

言歸正傳,現(xiàn)在我們就帶著 React View 怎么實(shí)現(xiàn)這個(gè)問題來解讀源碼。

React-View 源碼解讀 配置

配置是設(shè)計(jì)的源頭之一,一切源碼都可以從配置入手研究。

var defaultOptions = {
  doctype: "",
  beautify: false,
  cache: process.env.NODE_ENV === "production",
  extname: "jsx",
  writeResp: true,
  views: path.join(__dirname, "views"),
  internals: false
};

如果我們用過像 handlebars 或是 jade View,我們看到 React View 的配置與其它 View 的配置有幾點(diǎn)不同。doctype、internals 這些配置都是其它模板引擎不會有的。

模板常用的配置應(yīng)該是什么呢?

viewPath,在上述配置指的是 view,就是 View 的目錄在哪里,這是每一個(gè)模板插件或中間件都需要去配的。

extname,后綴名是什么,一般來說模板引擎都有自己獨(dú)有的后綴,當(dāng)然不排除可以有喜好選擇的情況。比如對 React 而言,就可以寫成是 .jsx.js 兩種不同的形式。

cache,我想一般模板引擎都會帶 cache 功能,因?yàn)槟0宓慕馕鍪切枰馁M(fèi)資源的,而模板本身的改動的頻度是非常低的。每當(dāng)發(fā)布的時(shí)候,我們?nèi)ニ⑿乱淮文0寮纯?。但上述配置中?cache 并不是指這個(gè),我們等讀源碼時(shí)再來看。

渲染

標(biāo)準(zhǔn)的渲染過程其實(shí)非常的簡單。對于 React 來說就是讀取目錄下的文件,像前端加載一樣,require 那個(gè)文件。最后利用 ReactDOMServer 中的方法來渲染。

var render = internals
  ? ReactDOMServer.renderToString
  : ReactDOMServer.renderToStaticMarkup;

...

var markup = options.doctype || "";
try {
  var component = require(filepath);
  // Transpiled ES6 may export components as { default: Component }
  component = component.default || component;
  markup += render(React.createElement(component, locals));
} catch (err) {
  err.code = "REACT";
  throw err;
}

if (options.beautify) {
  // NOTE: This will screw up some things where whitespace is important, and be
  // subtly different than prod.
  markup = beautifyHTML(markup);
}

var writeResp = locals.writeResp === false
    ? false
    : (locals.writeResp || options.writeResp);
      
if (writeResp) {
  this.type = "html";
  this.body = markup;
}

return markup

這里我們截取最關(guān)鍵的片段,正如我們預(yù)估的渲染過程一樣。但我們看到,從流程上看有四個(gè)細(xì)節(jié):

設(shè)置 doctype 的目的

在一般模板中我們很少看到將 doctype 放在配置中配置,但因?yàn)?React 的特殊性,讓我們不得不這么做。原因很簡單,React render 方法返回時(shí)一定需要一個(gè)包裹的元素,比如 div,ul,甚至 html,因此,我們需要手動去加 doctype。

渲染 React 組件

renderToStringrenderToStaticMarkup 都是 "react-dom/server" 下的方法,與 render 不同,render 方法需要指定具體渲染到 DOM 上的節(jié)點(diǎn),但那兩個(gè)方法都只返回一段 HTML 字符串。這一點(diǎn)讓 React 成為模板語言而存在。它們兩個(gè)方法的區(qū)別在于:

renderToString 方法渲染的時(shí)候帶有 data-reactid 屬性,意味著可以做 server render,React 在前端會認(rèn)識服務(wù)端渲染的內(nèi)容,不會重新渲染 DOM 節(jié)點(diǎn),開始執(zhí)行 componentDidMount 繼續(xù)執(zhí)行后續(xù)生命周期。

renderToStaticMarkup 方法渲染時(shí)沒有 data-reactid,把 React 當(dāng)做是純模板來使用,這個(gè)時(shí)候只渲染 body 外的框架是比較合適的。

render 方法里,我們看到 React.createElement 方法。是因?yàn)樵诜?wù)端 render 方法沒有 babel 編譯,因此寫的其實(shí)是 編譯后的代碼。

美化 HTML

options.beautify 配置了我們是否要美化 HTML,默認(rèn)時(shí)是關(guān)閉的。任何需要編譯的模板引擎一般都會有類似的配置。在 Reat 中,因?yàn)?render 后的代碼是一連串的字符串,返回到前臺的時(shí)候都是無法閱讀的代碼。在有必要時(shí),我們可以開啟這個(gè)配置。

綁定到上下文

最后一步,盡管有一個(gè)開關(guān)控制,但我們看到最后是把內(nèi)容綁定到 this.body 下的。 這里省略了整個(gè)實(shí)現(xiàn)過程是在 app.context.render 方法下,即是重寫了 app.context 下的 render 方法,用于渲染 React。如果說 app.context.render 方法是 function*,那么我們的 react-view,就會變?yōu)橹虚g件。

Cache

我們從一開始就看到了配置中就有 cache 配置,這個(gè) cache 是不是我們所想呢?我們來看下源代碼:

// match function for cache clean
var match = createMatchFunction(options.views);

...

if (!options.cache) {
  cleanCache(match);
}

這里的 cache 指的是模板緩存么。事實(shí)上不完全是,我們來看一下 cleanCache 方法就明白了:

function cleanCache(match) {
  Object.keys(require.cache).forEach(function(module) {
    if (match(require.cache[module].filename)) {
      delete require.cache[module];
    }
  });
}

因?yàn)槲覀冏x取 React 文件用的是 require 方法,而在 Node 中 require 方法是有緩存的,Node 在每個(gè)第一次 Load Module 時(shí)就會將該 Module 緩存,存入全局的 _cache 中,在一般情況下我們當(dāng)然需要這么做。但在模板加載這個(gè)情景下就不同了。

在這里的確我們?nèi)志彺媪?React 模板文件,但這個(gè)文件是編譯前的文件。而我們需要緩存的是編譯后的文件,也就是說 markup 是我們需要緩存的值。

在這里我們想想怎么去實(shí)現(xiàn),方便起見,我們可以新增一個(gè) lru-cache,用它的好處是 lru 封裝了很多關(guān)于 cache 時(shí)效與容量的開關(guān)。

var LRU = require("lru-cache");
var cache = LRU(this.options.cacheOptions);

...

if (options.cache && cache.get(filepath)) {
  markup = cache.get(filepath);
} else {
  var markup = options.doctype || "";
  try {
    var component = require(filepath);
  } else {
      // Transpiled ES6 may export components as { default: Component }
      component = component.default || component;
      markup += render(React.createElement(component, locals));
    }
  } catch (err) {
    err.code = "REACT";
    throw err;
  }

  // beautify ...
  
  if (options.cache) {
    cache.set(filepath, markup);
  }
}

當(dāng)然,我們現(xiàn)在這種情形下都需要清除 require 的 cache。

Babel

我想很多開發(fā)者在寫 React 組件的時(shí)候用的是 ES6 Class 來寫的,而且會用到很多 ES6/ES7 的方法,不巧的是 Node 還不支持有些高級特性。因此就引到了一個(gè)話題,服務(wù)端怎么引用 babel?

在業(yè)務(wù)有 babel-node 這類解決方案,但這畢竟是一個(gè)實(shí)驗(yàn)性的 Node,我們不會拿生產(chǎn)環(huán)境去冒險(xiǎn)。

在 koa/react-view 中間件內(nèi),有一段說明,它建議開發(fā)者在使用的時(shí)候加入 babel-register 作實(shí)時(shí)編譯。關(guān)于這個(gè)問題,當(dāng)然也可以寫在中間件內(nèi),在加載模板前引入。隨著 Node 對 ES6 方法支持的完善,也許有一天也用不到了。

總結(jié)

其實(shí),實(shí)現(xiàn) View 非常簡單,我們也從一些維度看到了設(shè)計(jì)一個(gè) xx-view 的一般方法。在具體實(shí)現(xiàn)的時(shí)候,我們可以用一些更好的方法去做,比如用類來抽象 View,用 Promise 來描述過程。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/79567.html

相關(guān)文章

  • React 同構(gòu)實(shí)踐與思考

    摘要:后面會利用這個(gè)框架來做實(shí)踐。接下來就是我們要繼續(xù)探討的同構(gòu)同構(gòu)數(shù)據(jù)處理的探討我們都知道,瀏覽器端獲取數(shù)據(jù)需要發(fā)起請求,實(shí)際上發(fā)起的請求就是對應(yīng)服務(wù)端一個(gè)路由控制器。是有生命周期的,官方給我們指出的綁定,應(yīng)該在里來進(jìn)行。 眾所周知,目前的 WEB 應(yīng)用,用戶體驗(yàn)要求越來越高,WEB 交互變得越來越豐富!前端可以做的事越來越多,去年 Node 引領(lǐng)了前后端分層的浪潮,而 React 的出現(xiàn)...

    MageekChiu 評論0 收藏0
  • 你不能不知道的Koa實(shí)現(xiàn)原理

    摘要:前言什么這是一篇源碼解讀文章那一定很枯燥不看。通過利用函數(shù),幫你丟棄回調(diào)函數(shù),并有力地增強(qiáng)錯(cuò)誤處理。并沒有捆綁任何中間件,而是提供了一套優(yōu)雅的方法,幫助您快速而愉快地編寫服務(wù)端應(yīng)用程序。 showImg(https://segmentfault.com/img/bVNQYf?w=1020&h=790); 前言 什么?這是一篇源碼解讀文章 ? 那一定很枯燥!不看。 我把 Koa 的核心實(shí)...

    LinkedME2016 評論0 收藏0
  • KOA2框架原理解析和實(shí)現(xiàn)

    摘要:實(shí)現(xiàn)的四大模塊上文簡述了源碼的大體框架結(jié)構(gòu),接下來我們來實(shí)現(xiàn)一個(gè)的框架,筆者認(rèn)為理解和實(shí)現(xiàn)一個(gè)框架需要實(shí)現(xiàn)四個(gè)大模塊,分別是封裝創(chuàng)建類構(gòu)造函數(shù)構(gòu)造對象中間件機(jī)制和剝洋蔥模型的實(shí)現(xiàn)錯(cuò)誤捕獲和錯(cuò)誤處理下面我們就逐一分析和實(shí)現(xiàn)。 什么是koa框架? ? ? ? ?koa是一個(gè)基于node實(shí)現(xiàn)的一個(gè)新的web框架,它是由express框架的原班人馬打造的。它的特點(diǎn)是優(yōu)雅、簡潔、表達(dá)力強(qiáng)、自由度...

    tracymac7 評論0 收藏0
  • KOA2框架原理解析和實(shí)現(xiàn)

    摘要:實(shí)現(xiàn)的四大模塊上文簡述了源碼的大體框架結(jié)構(gòu),接下來我們來實(shí)現(xiàn)一個(gè)的框架,筆者認(rèn)為理解和實(shí)現(xiàn)一個(gè)框架需要實(shí)現(xiàn)四個(gè)大模塊,分別是封裝創(chuàng)建類構(gòu)造函數(shù)構(gòu)造對象中間件機(jī)制和剝洋蔥模型的實(shí)現(xiàn)錯(cuò)誤捕獲和錯(cuò)誤處理下面我們就逐一分析和實(shí)現(xiàn)。 什么是koa框架? ? ? ? ?koa是一個(gè)基于node實(shí)現(xiàn)的一個(gè)新的web框架,它是由express框架的原班人馬打造的。它的特點(diǎn)是優(yōu)雅、簡潔、表達(dá)力強(qiáng)、自由度...

    liangzai_cool 評論0 收藏0

發(fā)表評論

0條評論

zxhaaa

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<