Web和Android中的Reactive


目錄

緣起

筆者剛入行的時候,作的是Android客戶端開發。雖然從事的時間不長,但稍微瞭解一點基本的概念。後來陰差陽錯從事Web開發,一直到如今,因此如今多多少少對Web領域有一丁點的看法。由於這樣,因此有時候會思考下兩者的共性,想找一下兩者相同的點。最近有兩個問題,一直縈繞着:javascript

  1. React中有stateprops的概念。組件component的顯示,數據的體現 大部分都是由state承載,props傳遞。而android基本都是經過setXX去控制組件和數據。爲何會有這樣的差別?
  2. 同時,redux等狀態管理組件都是 flux架構的實現,也有不少開發者提出FluxAndroid的概念,但google官方並不認可flux的架構。這是爲何?

Android開發中的常見寫法

咱們常常看到這樣的寫法,首先在xml文件中定義咱們的佈局文件,指定id等屬性。html

<TextView android:text="@string/hello_world"
          android:id="@+id/textview"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content" />
複製代碼

同時,在Activity中經過findViewById去獲取控件的引用,而後進行一系列操做,好比setTextvue

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView textView = (TextView) findViewById(R.id.textview);
        TextView textView = new TextView(this);
        textView.setText("Hey, one more TextView");

    }
複製代碼

除此以外,咱們還常常看見這樣的寫法,好比:java

setVisibility(View.VISIBLE);
複製代碼
imageview.setBackgroundColor(Color.rgb(213, 0, 0));
複製代碼

你有沒有發現,這些寫法有一個共性,就是都是經過setXXX去設定值。也就是說,咱們開發者在操做的時候,有這樣的一個模式:react

  1. 獲取到值(不論是從數據庫仍是網絡拉取)
  2. 這個值通過處理,獲得能夠目標控件須要的值
  3. 經過setXXX去設定該值
  4. 而後界面發生變化

後來我發現,這樣的模式在JQuery中也是相似的。jquery

JQuery中的常見寫法

先看下這段代碼。android

<!DOCTYPE html>
<html lang="en">
<head>
    <title>learn jQuery</title>
</head>
<body>

    <h1>例子1</h1>
    <p>若是你點我,我就會消失。</p>
    <p>繼續點我!</p>
    <p>接着點我!</p>

    <script src="jquery-3.3.1.js"></script>
    <script type="text/javascript">
       //例子1
       $(document).ready(function () {
           console.log("document is ready");
           $("p").click(function () {
               $(this).hide();
           });
       });
    </script>
</body>
</html>

複製代碼

首先,咱們先寫了四行HTML代碼。 而後,經過JQuery去操做,注意咱們的操做方式。git

咱們經過$("p") 去獲取document對象中的<p></p>元素,這是否是很像剛剛在上一節提到的findViewById,有木有?github

獲取到元素後,經過$(this).hide()對該元素進行操做。這像不像textView.setText("Hey, one more TextView");數據庫


若是以爲這段代碼不直觀,來看這個。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Evan JQery</title>
    <script src="jquery-3.3.1.js"></script>
    <script>
        $(document).ready(function(){
            $("#btn1").click(function(){
                $("#test1").text("Hello world!");
            });
            $("#btn2").click(function(){
                $("#test2").html("<b>Hello world!</b>");
            });
            $("#btn3").click(function(){
                $("#test3").val("Dolly Duck");
            });
        });
    </script>
</head>
<body>
<p id="test1">這是段落。</p>
<p id="test2">這是另外一個段落。</p>
<p>Input field: <input type="text" id="test3" value="Mickey Mouse"></p>
<button id="btn1">設置文本</button>
<button id="btn2">設置 HTML</button>
<button id="btn3">設置值</button>

</body>
</html>

複製代碼

同時,你能夠再本地打開上面的代碼,在瀏覽器中預覽,而後打開開發者模式,在控制檯中輸入,

$("#test3").val("Dolly Ducrrrrk");
複製代碼

你會發現網頁內容也隨之發生了改變。

命令式編程

維基百科這樣說:

Imperative programming is a programming paradigm that uses statements that change a program’s state.

簡單理解,命令式編程,就是命令「機器」如何去作事情(how),這樣無論你想要的是什麼(what),它都會按照你的命令實現。

上述了兩小節都是命令式編程。

聲明式編程

提到命令式編程,不得不說下聲明式編程。

聲明式編程,就是告訴「機器」你想要的是什麼(what),讓機器想出如何去作(how)。

打個比方:

Declarative Programming is like asking your friend to draw a landscape. You don’t care how they draw it, that’s up to them. Imperative Programming is like your friend listening to Bob Ross tell them how to paint a landscape. While good ole Bob Ross isn’t exactly commanding, he is giving them step by step directions to get the desired result.

聲明式就像你告訴你朋友畫一幅畫,你不用去管他怎麼畫的細節

命令式就像按照你的命令,你朋友一步步把畫畫出來

若是你以爲有點分不清楚兩者區別,彆着急,先看下下面的案例。

React中的常見寫法

(完成源碼將放在文末可下載)

'use strict';

const e = React.createElement;

class LikeButton extends React.Component {
  //https://www.cnblogs.com/johnzhu/p/9016277.html
  constructor(props) {
    super(props);
    this.state = { liked: false };
  }

  render() {
    if (this.state.liked) {
      return 'You liked this.';
    }

    return e(
      'button',
      { onClick: () => this.setState({ liked: true }) },
      'Like'
    );
  }
}

const domContainer = document.querySelector('#like_button_container');
ReactDOM.render(e(LikeButton), domContainer);

複製代碼

React是聲明式的,以上就是體現聲明式很好的例子。

在咱們的render方法中,渲染一個按鈕,按鈕名字爲「Like」。

按鈕的狀態(也就是文字內容)受state控制,初始化的state爲一個JavaScript對象。

this.state = { liked: false };
複製代碼

點擊按鈕以後,觸發事件,改變state

{ onClick: () => this.setState({ liked: true }) }
複製代碼

好,state在點擊先後發生改變,按鈕的文字是由state控制。 換句話說,咱們並無直接操做DOM去改變按鈕的文字內容,只是經過改變state的狀態。 而state不一樣的值描述了按鈕在不一樣狀況下應該如何表現不一樣的內容。

The differences here may be subtle. The React example never actually touches an element. it simply declares an element should be rendered given our current state. It does not actually manipulate the DOM itself.

和命令式的區別有點模糊。React沒有直接操做元素,它只是聲明瞭元素如何在給定的狀態下渲染出特定的結果。

因此,React的思想和JQuery有很大不一樣。

When writing React, it’s often good not to think of how you want to accomplish a result, but instead what the component should look like in it’s new state.

使用React的時候,最好不一樣去想着如何實現某個結果,而是組件在新的狀態下應該有什麼樣的表現。


歇一口氣 ^ __ ^ 歇一口氣


Vue的常見寫法

看了React的寫法,知道它是聲明式,那咱們來看看Vue是如何體現響應式的。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>VueTest -- evan</title>
</head>
<body>

    <div id="app">
       <h2>{{product}} are in stock</h2>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>

        const app = new Vue({
            el: '#app',  /*element的縮寫*/
            data: {
                product: 'Boots'
            }
        })

    </script>

</body>
</html>

複製代碼

咱們在模板中指定

<h2>{{product}} are in stock</h2>
複製代碼

而後再Vue實例中只要product有值,立馬就渲染出來。

爲了更好的演示,請你打開上述代碼,在瀏覽器中預覽,而後打開控制檯。輸入

app.product = 'you input here'
複製代碼

你就會發現屏幕上的網頁渲染立馬發生了改變。

這就是響應式。

Vue

Vue 最獨特的特性之一,是其非侵入性的響應式系統。數據模型僅僅是普通的 JavaScript 對象。而當你修改它們時,視圖會進行更新。

來咱們簡單解釋下 Vue 響應式系統的底層細節。

第一,還記得咱們經過下面的代碼,把一個普通的 JavaScript 對象傳入 Vue 實例做爲 data 選項。

const app = new Vue({
            el: '#app',  /*element的縮寫*/
            data: {
                product: 'Boots'
            }
        })
複製代碼

Vue 將遍歷此對象全部的屬性。

第二,Vue使用 Object.defineProperty 把這些屬性所有轉爲 getter/setter。

第三,每一個Vue Component的render函數,都都對應一個 watcher 實例。

第四,當 Vue Component render 函數被執行的時候, data 上會被 觸碰(touch), 即被讀, getter 方法會被調用, 此時 Vue 會去記錄此 Vue component 所依賴的全部 data。(這一過程被稱爲依賴收集)。

第五,data 被改動時(主要是用戶操做), 即被寫, setter 方法會被調用, 此時 Vue 會去通知全部依賴於此 data 的組件去調用他們的 render 函數進行更新。

你確定熟悉響應式

還記當時風靡一時的RxJava, RxAndroid嘛?現在又有了RxKotlin,RxDart。(提醒和我同樣,作過Android開發的同窗們,哈哈~) 他們都是ReactiveX家族的一員。

ReactiveX

試着回答

React中有stateprops的概念。組件component的顯示,數據的體現 大部分都是由state承載,props傳遞。而android基本都是經過setXX去控制組件和數據。爲何會有這樣的差別?

我的愚見,Android客戶端和Web開發中,有這麼幾點不一樣:

  1. Android的界面UI是有XML標籤訂義,和DOM有些不一樣。

  2. 瀏覽器刷新的時候,整個DOM結構都會更新,而Android沒有刷新整個頁面的概念,在Android中,你是經過measure (測量)、layout (定位)、draw (繪製)去顯示一個View

  3. 不一樣於React中的Component,Android中的View,好比ImageViewTextView 自己內置了不少方法來控制自身屬性,好比setBackgroundsetText

  4. (歡迎大佬斧正、補充)


redux等狀態管理組件都是 flux架構的實現,也有不少開發者提出FluxAndroid的概念,但google官方並不認可flux的架構。這是爲何?

先簡單說明下,Android的架構。

Android架構合集 這篇文章中列舉了不少Android架構,包括官方google的,同時也有Flux架構模式。

不少開發者受Flux的啓發,寫了適用Android的Flux架構模式。 好比下面幾篇文章。

AndroidFlux ——當ANDROID遇到了FLUX,架構ANDROID應用的新方式。 Flux Architecture on Android

RxFlux Android Architecture

Flux Android Architecture Components using Kotlin

這個問題我尚未很好的答案。我本身以Flux的架構模式去作過了Android的實踐,因爲Android Activity等自身的組件,使得用Flux架構反而比較繁瑣,有點過分設計的味道。但究竟爲什麼Google官方不推薦,歡迎你們補充~

彩蛋

在這裏插入圖片描述
這就是 Dan 所說的,React 並非徹底的響應式設計的意思。React 須要你手動跟蹤應用數據,並在數據變化時告訴 React,這也意味着你得作更多工做。

難道這就是Vue這個響應式框架近幾年愈來愈流行的緣由?

放出彩蛋,就是svelte

svelte

![在這裏插入圖片描述](img-blog.csdnimg.cn/20190730220… =300x300)

哦對了,文中全部的源碼在這裏哈 點我下載

參考

Imperative programming --維基百科

Declarative vs Imperative Programming --Ian Mundy

聲明式和命令式 --小豬ab

Reactivity in Depth --Vue官方文檔

Vue 響應式原理白話版

React 不是真正的響應式編程,Svelte 纔是 --Ovie Okeh

相關文章
相關標籤/搜索