网友真实露脸自拍10p,成人国产精品秘?久久久按摩,国产精品久久久久久无码不卡,成人免费区一区二区三区

小程序模板網(wǎng)

hooks 在微信小程序中的試驗(yàn)

發(fā)布時(shí)間:2018-11-27 17:39 所屬欄目:小程序開發(fā)教程

前段時(shí)間 react hooks 特性刷得沸沸揚(yáng)揚(yáng)的,看起來挺有意思的,估計(jì)不少其他框架也會(huì)逐步跟進(jìn),所以也來嘗試一下能不能用在小程序上。

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

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>
  );
}

函數(shù)式組件本身非常簡潔,不維護(hù)生命周期和狀態(tài),是一個(gè)可以讓性能得以優(yōu)化的使用方式。但是在之前這種方式只能用于純展示組件或者高階組件等,它很難實(shí)現(xiàn)一些交互行為。但是在 hooks 出現(xiàn)之后,你就可以為所欲為了。

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

hooks 的使用目前有兩個(gè)限制:

  • 只能在函數(shù)式組件內(nèi)或其他自定義 hooks 內(nèi)使用,不允許在循環(huán)、條件或普通 js 函數(shù)中調(diào)用 hooks。
  • 只能在頂層調(diào)用 hooks 。

這個(gè)限制和 hooks 的實(shí)現(xiàn)方式有關(guān),下面小程序 hooks 也會(huì)有同樣限制,原因應(yīng)該也是類似的。為了能讓開發(fā)者更好的使用 hooks,react 官方也提供了一套 eslint 插件來協(xié)助我們開發(fā): reactjs.org/docs/hooks-… 。

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

函數(shù)式組件

小程序沒有提供函數(shù)式組件,這倒是很好理解,小程序的架構(gòu)是雙線程運(yùn)行模式,邏輯層執(zhí)行 js 代碼,視圖層負(fù)責(zé)渲染。那么聲明在邏輯層的自定義組件要渲染在視圖層必須保證來兩個(gè)線程都存在自定義組件實(shí)例并一一對(duì)應(yīng),這樣的架構(gòu)已經(jīng)成熟,目前對(duì)函數(shù)式組件并沒有強(qiáng)烈的需求。在基礎(chǔ)庫不大改的情況下,就算提供了函數(shù)式組件也只是提供了另一種新寫法而已,本質(zhì)上的實(shí)現(xiàn)沒有區(qū)別也不能提升什么性能。

不過也不排除以后小程序會(huì)提供一種只負(fù)責(zé)渲染不維護(hù)生命周期不做任何邏輯的特殊組件來優(yōu)化渲染性能,這種的話本質(zhì)上就和函數(shù)式組件類似了,不過函數(shù)式組件較為極端的是在理論上是有辦法做到無實(shí)例的,這個(gè)在小程序中怕是有點(diǎn)困難。

言歸正傳,小程序沒有提供函數(shù)式組件,那么就強(qiáng)行封裝出一個(gè)寫法好了,假設(shè)我們有一個(gè)自定義組件,它的 js 和 wxml 內(nèi)容分別是這樣的:

// 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>

一個(gè)很奇葩的例子,但是能看明白就行。小程序里視圖和邏輯分離,不像 react 可以將視圖和邏輯寫到一起,那么小程序里的函數(shù)式組件里想返回一串渲染邏輯就不太科學(xué)了,這里就改成返回要用于渲染的 state 和方法。

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

FunctionComponent 函數(shù)其實(shí)就相當(dāng)于封裝了小程序原有的 Component 構(gòu)造器,它的實(shí)現(xiàn)類似這樣:

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

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

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

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

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

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

實(shí)現(xiàn)很簡單,就是在 attached 的時(shí)候跑一下傳入的函數(shù),拿到 state 和方法后設(shè)置到自定義組件實(shí)例上就行。其中 currentCompInst 和 callIndex 在 useState 和 useEffect 的實(shí)現(xiàn)上會(huì)用到,下面來介紹。

useState 和 useEffect

這里的一個(gè)難點(diǎn)是,useState 是沒有指定變量名的。初次渲染還好,二次渲染的話要找回這個(gè)變量就要費(fèi)一段代碼了。

PS:后續(xù)的實(shí)現(xiàn)除了參考了 react 的 hooks 外,也參考了 vue-hooks 的嘗試,有興趣的同學(xué)也可以去觀摩一下。

這里上面提到的 currentCompInst 和 callIndex,將上一次的變量存儲(chǔ)在 currentCompInst 中,用 callIndex 記錄調(diào)用 useState 和 useEffect 的順序,這樣就可以在二次渲染的時(shí)候通過順序找回上一次使用的變量:

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 事件回調(diào)
    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]
}
復(fù)制代碼

useEffect 的實(shí)現(xiàn)邏輯也類似,這里就不再貼代碼了。小程序本身沒有提供 render 函數(shù),調(diào) FunctionalComponent 聲明函數(shù)式組件傳入的函數(shù)就作為 render 函數(shù)來用。每次調(diào) setXXX 方法——也就是上面代碼中返回的 updater 的時(shí)候,找到原本存儲(chǔ)這個(gè) state 的地方存儲(chǔ)進(jìn)去,然后再次執(zhí)行 render 函數(shù),進(jìn)行組件的渲染。

到這里應(yīng)該就明白了,對(duì)于 hooks 使用為什么會(huì)有一開始的那兩條限制。如果在一些條件、循環(huán)等語句內(nèi)使用 hooks,就無法確保 state 的順序,再二次渲染時(shí)就不一定能找回對(duì)應(yīng)的 state。



易優(yōu)小程序(企業(yè)版)+靈活api+前后代碼開源 碼云倉庫:starfork
本文地址:http://www.xiuhaier.com/wxmini/doc/course/24977.html 復(fù)制鏈接 如需定制請(qǐng)聯(lián)系易優(yōu)客服咨詢:800182392 點(diǎn)擊咨詢
QQ在線咨詢
AI智能客服 ×