午夜91福利视频,午夜成人在线观看,午夜在线视频免费观看,午夜福利短视频,精品午夜成人免费视频APP

小程序模板網

hooks 在微信小程序中的試驗

發布(bu)時間(jian):2018-11-27 17:39 所屬欄目:小程序開發教程

前段(duan)時間 react hooks 特性刷(shua)得沸沸揚揚的(de),看起(qi)來(lai)挺有意思的(de),估計不(bu)少其他框(kuang)架也(ye)會逐步跟進,所以也(ye)來(lai)嘗試一(yi)下能不(bu)能用在小(xiao)程序上(shang)。

react hooks 允許你在函數式(shi)組件中使(shi)用(yong) state,用(yong)一段官方的簡單例子(zi)概括如下:

import { useState } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

函數式組(zu)件(jian)本身非(fei)常簡(jian)潔(jie),不維(wei)護(hu)生命(ming)周期(qi)和狀態,是(shi)一(yi)個可以讓性能得以優化(hua)的(de)使用(yong)方式。但(dan)是(shi)在之前這種方式只能用(yong)于純展(zhan)示組(zu)件(jian)或者(zhe)高階組(zu)件(jian)等,它很難實現一(yi)些交互行為。但(dan)是(shi)在 hooks 出現之后(hou),你就可以為所欲為了(le)。

 這里(li)有(you)一份官(guan)方的文檔,不明圍觀(guan)群眾有(you)興趣(qu)的可以點進去了解一下: reactjs.org/docs/hooks-… 。

hooks 的使(shi)用(yong)目(mu)前(qian)有兩個限制:

  • 只能在函數式組件內或其他自定義 hooks 內使用,不允許在循環、條件或普通 js 函數中調用 hooks。
  • 只能在頂層調用 hooks 。

這個(ge)限(xian)制和 hooks 的實現方式(shi)有(you)(you)關(guan),下面小程序 hooks 也會有(you)(you)同樣(yang)限(xian)制,原因應(ying)該也是類似的。為了能讓開(kai)發者更(geng)好(hao)的使用 hooks,react 官(guan)方也提供了一套 eslint 插件(jian)來協助我們開(kai)發: reactjs.org/docs/hooks-&hellip; 。

下面就來介紹下在小程序中的嘗試~

函數式組件

小(xiao)程(cheng)序(xu)沒有(you)(you)提供函數(shu)式組(zu)件(jian),這倒(dao)是(shi)很好理(li)解,小(xiao)程(cheng)序(xu)的(de)(de)架(jia)構是(shi)雙線程(cheng)運行模式,邏輯(ji)層執(zhi)行 js 代碼,視圖層負責(ze)渲染。那么聲明在(zai)(zai)邏輯(ji)層的(de)(de)自定義(yi)組(zu)件(jian)要渲染在(zai)(zai)視圖層必須保(bao)證(zheng)來兩個線程(cheng)都(dou)存在(zai)(zai)自定義(yi)組(zu)件(jian)實(shi)例并一一對(dui)應,這樣的(de)(de)架(jia)構已(yi)經(jing)成(cheng)熟(shu),目前對(dui)函數(shu)式組(zu)件(jian)并沒有(you)(you)強(qiang)烈的(de)(de)需求。在(zai)(zai)基礎庫(ku)不大改的(de)(de)情況下,就算提供了(le)函數(shu)式組(zu)件(jian)也(ye)只(zhi)是(shi)提供了(le)另一種新寫法而(er)已(yi),本(ben)質上的(de)(de)實(shi)現沒有(you)(you)區別也(ye)不能提升什么性能。

不過也(ye)不排除以后小(xiao)程序會提供一種只負(fu)責渲(xuan)染不維(wei)護生命(ming)周期不做(zuo)任何(he)邏(luo)輯的(de)特殊(shu)組件來優化渲(xuan)染性能,這種的(de)話本質上就和函(han)數式(shi)(shi)組件類似了(le),不過函(han)數式(shi)(shi)組件較為(wei)極端的(de)是在(zai)理論(lun)上是有辦法做(zuo)到無實例的(de),這個在(zai)小(xiao)程序中(zhong)怕(pa)是有點困難(nan)。

言歸(gui)正傳,小程(cheng)序(xu)沒有提供(gong)函數式組件(jian),那么就強行封裝出一(yi)個(ge)寫法好了,假(jia)設我(wo)們有一(yi)個(ge)自定義組件(jian),它的 js 和 wxml 內容(rong)分別是這(zhe)樣(yang)的:

// component.js
const {useState, useEffect, FunctionalComponent} = require('miniprogram-hooks') 

FunctionalComponent(function() {
  const [count, setCount] = useState(1)

  useEffect(() => {
    console.log('count update: ', count)
  }, [count])

  const [title, setTitle] = useState('click')

  return {
    count,
    title,
    setCount,
    setTitle,
  }
})

<!-- component.wxml -->
<view>{{count}}</view>
<button bindtap="setCount" data-arg="{{count + 1}}">{{title}}</button>
<button bindtap="setTitle" data-arg="{{title + '(' + count + ')'}}">update btn text</button>

一個很奇葩的(de)例(li)子,但是能看明(ming)白就行。小程序里(li)視(shi)圖(tu)和(he)邏(luo)輯分離,不像 react 可以將(jiang)視(shi)圖(tu)和(he)邏(luo)輯寫到(dao)一起,那么小程序里(li)的(de)函數式組件里(li)想(xiang)返回(hui)一串(chuan)渲染邏(luo)輯就不太科學了,這里(li)就改成返回(hui)要用于渲染的(de) state 和(he)方法。

PS:wxml 里不支持 bindtap="setCount(count + 1)" 這種寫法(fa),所以參數(shu)就走(zou) dataset 的(de)方式傳入了。

FunctionComponent 函數其實就相當于封(feng)裝了(le)小程(cheng)序(xu)原有的 Component 構造器,它(ta)的實現類似(si)這樣:

function FunctionalComponent(func) {
  func = typeof func === 'function' ? func : function () {}

  // 定義自定義組件
  return Component({
    attached() {
      this._$state = {}
      this._$effect = {}
      this._$func = () => {
        currentCompInst = this // 記錄當前的自定義組件實例
        callIndex = 0 // 初始化調用序號
        const newDef = func.call(null) || {}
        currentCompInst = null

        const {data, methods} = splitDef(newDef) // 拆分 state 和方法

        // 設置 methods
        Object.keys(methods).forEach(key => {
          this[key] = methods[key]
        })

        // 設置 data
        this.setData(data)
      }

      this._$func()
    },
    detached() {
      this._$state = null
      this._$effect = null
      this._$func = null
    }
  })
}
復制代碼

實現很簡(jian)單,就是在 attached 的時候跑一下(xia)傳入的函數,拿到(dao) state 和方法(fa)后(hou)設置到(dao)自定義組件實例上就行。其中(zhong) currentCompInst 和 callIndex 在 useState 和 useEffect 的實現上會用(yong)到(dao),下(xia)面來介紹。

useState 和 useEffect

這里的(de)(de)一(yi)個難點(dian)是,useState 是沒有指定變量(liang)名的(de)(de)。初次(ci)渲染還好,二次(ci)渲染的(de)(de)話(hua)要找回這個變量(liang)就(jiu)要費一(yi)段代碼了。

 PS:后續的(de)實現除了(le)參(can)考(kao)了(le) react 的(de) hooks 外,也參(can)考(kao)了(le) vue-hooks 的(de)嘗試,有興(xing)趣(qu)的(de)同學(xue)也可以去觀摩一下(xia)。

這里上面提(ti)到的(de) currentCompInst 和 callIndex,將上一次的(de)變(bian)量存儲在(zai) currentCompInst 中,用 callIndex 記錄調用 useState 和 useEffect 的(de)順(shun)序(xu),這樣(yang)就可以在(zai)二(er)次渲(xuan)染(ran)的(de)時(shi)候通過(guo)順(shun)序(xu)找回上一次使用的(de)變(bian)量:

function useState(initValue) {
  if (!currentCompInst) throw new Error('component instance not found!')

  const index = callIndex++
  const compInst = currentCompInst

  if (compInst._$state[index] === undefined) compInst._$state[index] = initValue

  const updater = function (evt) {
    let value = evt

    // wxml 事件回調
    if (typeof evt === 'object' && evt.target && evt.currentTarget) {
      const dataset = evt.currentTarget.dataset
      value = dataset && dataset.arg
    }

    // 存入緩存
    compInst._$state[index] = value
    compInst._$func()
  }
  updater._isUpdater = true

  return [compInst._$state[index], updater]
}
復制代碼

useEffect 的(de)實現邏輯也類似,這(zhe)里就不再貼代碼了。小程(cheng)序本身(shen)沒有提供 render 函(han)數(shu),調 FunctionalComponent 聲明函(han)數(shu)式組件傳入的(de)函(han)數(shu)就作(zuo)為 render 函(han)數(shu)來用。每次調 setXXX 方法——也就是(shi)上面(mian)代碼中返回的(de) updater 的(de)時(shi)候,找到原本存儲這(zhe)個 state 的(de)地方存儲進(jin)去,然后再次執行 render 函(han)數(shu),進(jin)行組件的(de)渲染(ran)。

到這里應(ying)(ying)該就(jiu)明(ming)白了(le),對于 hooks 使(shi)用(yong)為(wei)什么會有一開始的(de)那兩條(tiao)限(xian)制(zhi)。如(ru)果在一些條(tiao)件、循環等語句(ju)內使(shi)用(yong) hooks,就(jiu)無法確保(bao) state 的(de)順序,再二次渲(xuan)染(ran)時就(jiu)不一定能找回(hui)對應(ying)(ying)的(de) state。



易(yi)優小程序(企業版)+靈活api+前后代碼開源(yuan) 碼云倉庫(ku):
本文地址://www.jinyoudianli.com/wxmini/doc/course/24977.html 復制鏈接 如(ru)需定(ding)制請聯系易優客服咨詢:

工作日 8:30-12:00 14:30-18:00
周(zhou)六及(ji)部分節假日提供值班服務(wu)

易(yi)小(xiao)優(you)
轉人工 ×