本文摘選自 Rax 官網 rax.js.orgjavascript
Javascript 是一個單線程的編程語言,單線程的特色就是一次只能處理一件事情,當前代碼任務耗時執行會阻塞後續代碼的執行。異步編程則是一種事件驅動編程,請求調用函數或方法後,無需當即等待響應,能夠繼續執行其餘任務,而以前任務響應返回後能夠經過狀態、通知和回調來通知調用者。java
js 中的異步編程方法有回調函數、事件處理函數、觀察者、Promise、Generator、async等,接下來看下在 Rax 中經常使用的異步編程方法。git
import { createElement, render, useState, useEffect } from 'rax'; import View from 'rax-view'; import Text from 'rax-text'; function App() { const [count, setCount] = useState(0); useEffect(() => { setCount(count + 1); }, []); return ( <View> <Text >Hello Rax {count}!</Text> </View> ); } export default App; 複製代碼
咱們在 useEffect
這個 effect hook 中,傳入 callback,當組件 mount 時調用該 callback,設置 count ,並使用 state hook 更新本地 state。這就是 Rax 中一個經常使用的回調使用方式。github
import { createElement, render, useState, useEffect } from 'rax'; import View from 'rax-view'; import Text from 'rax-text'; function App() { const [count, setCount] = useState(1); function showAlert() { setTimeout(() => { alert('You clicked on: ' + count); }, 3000); } return ( <View> <Text onClick={() => setCount(count + 1)}>Add count: You clicked {count} times</Text> <Text onClick={showAlert}>Hello Rax,show alert!</Text> </View> ); } export default App; 複製代碼
若是咱們按照如下步驟操做:npm
此時 alert 彈出的 count 值仍是爲 2。alert 會取到點擊時 count 的狀態,其實組件函數在每次渲染時都會被調用,可是在每次調用中 count 值都是常量,並被賦值爲當前渲染中的狀態值。其實普通函數也是如此,屢次調用函數傳入不一樣的參數,那麼函數的每次調用也是取到傳入的參數值。編程
import { createElement, render, useState, useEffect } from 'rax'; import request from 'universal-request'; import Text from 'rax-text'; function App() { const [value, setValue] = useState(1); useEffect(() => { function getValue() { request({ url: 'https://httpbin.org/post', method: 'POST', headers: { 'Access-Control-Allow-Origin': '*' }, data: { value: 'Rax' }, timeout: 5000 }).then((result) => { const data = JSON.parse(result.data.data); // setValue setValue(data.value); }).catch((error) => { }); } getValue(); }, []); return ( <Text>Current value: {value}</Text> ); } export default App; 複製代碼
經過一個網絡請求的例子已經很好的展現了 Promise 的使用方式,當首次 mount 以後發送請求,得到數據以後改變本地 state,觸發再次 render。Promise 也解決了回調地獄的問題,對併發執行很友好。 當咱們的異步操做任務較多時,會發現須要不斷的使用書寫 useEffect 等,增長了代碼量,此時咱們能夠抽離成自定義 hook ,只獲得咱們關心的數據。promise
import { useEffect, useState } from 'rax'; export default function usePromise(promise) { const [error, setError] = useState(null); const [result, setResult] = useState(null); useEffect( () => { let canceled = false; promise .then(r => { if (!canceled) { setResult(r); } }) .catch(e => { if (!canceled) { setError(e); } }); return () => { canceled = true; }; }, [promise] ); return [result, error]; } 複製代碼
自定義 hook usePromise,將 promise 做爲參數,並對組件銷燬時作了處理,usePromise 已經做爲 npm 包 rax-use-promise
發佈。 此時咱們再使用網絡請求時,只須要調用 usePromise 並獲取返回的 data 與 error 便可。markdown
import { createElement, render, useState, useEffect, useMemo } from 'rax'; import usePromise from 'rax-use-promise'; import request from 'universal-request'; import Text from 'rax-text'; const getValue = () =>request({ url: 'https://httpbin.org/post', method: 'POST', headers: { 'Access-Control-Allow-Origin': '*' }, data: { value: 'Rax' }, timeout: 5000 }).then(result => JSON.parse(result.data.data)); function App() { const [data, error] = usePromise(useMemo(getValue)); return ( <Text>Current value: {data.value}</Text> ); } export default App; 複製代碼
Hooks網絡