在Suspense結(jié)合使用取數(shù)邏輯

react在16.6推出了<Suspense>組件,看了官方文檔和一些分析文章,發(fā)現(xiàn)以后react的開發(fā)方式將會發(fā)生重大改變

Suspense功能

聲明方式等待任何內(nèi)容(組件),包括數(shù)據(jù),替代react-loadable做code spliting

Suspense 常見API

1.fallback:Suspense里面還有"任務"執(zhí)行時展示的UI
2.children: 一般是異步組件(配合lazy包裹的異步組件),為什么說一般是,因為官方?jīng)]提供穩(wěn)定的api來將取數(shù)邏輯跟Suspense配合出延遲效果,但我們可以hack

異步加載組件使用lazy(<MyComponent />)就一定要Suspense包裹,看了一些分析Suspense源碼的文章,了解到Suspense內(nèi)部是利用componentDidCatch來捕獲到lazy主動throw出來的Promise來做條件渲染,渲染fallback內(nèi)容,待lazy內(nèi)的Promise狀態(tài)resolve,完整內(nèi)容就渲染出來

// lazy內(nèi)部也是返回了Promise對象
const AsyncCompnentA = lazy(() => import('../componentA'))
export default () => {
  return (
    <Suspense fallback={<Loading />}>
       <AsyncCompnentA  />
    </Suspense>
 )
}

簡易理解中的Suspense源碼

class Suspense extends React.Component {
  state = {
     promise: null
  }
  componentDidCatch(e) {
    if(e instanceof Promise) {
        this.setState({
         promise: e,
       }, () => {
        e.then(() => {
           promise: null
        })
      })
    }
  }
  render() {
      return this.state.promise ? this.props.fallback : this.props.children
   }
}

不難理解,通過componentDidCatch捕獲的異常改變自身state,然后憑借promise值做條件渲染

而官方?jīng)]提供取數(shù)延遲,貌似暫時只開放給請求庫(swr)而非大眾調(diào)用者,但分析了一波源碼,利用throw promise也是可以模擬的

const PromiseThrower = () => {
  const getData = () => {
    const getData = fetch()
    getData.then(data => {
      returnData = data
    })
    if (returnData === cache) {
      throw getData
    }
    return returnData
  }
  return <>{getData()}</>
}

// useage
export default () => {
  return (
    <Suspense fallback={<Loading />}>
      <PromiseThrower />
    </Suspense>
  )
}

以往取數(shù)組件邏輯

以往loading跟取數(shù)(網(wǎng)絡請求)完全耦合,三目渲染、樣板代碼寫到吐

const AsyncComponentC = () => {
  const [loading, setLoading] = useState(false)
  useEffect(() => {
      setLoading(true)
      fetch('xxx').then(() => {
        setLoading(false)
     })
  }, [])
 return loading ? <Loading /> : <RealComponent />
}

未來使用猜想

對于一些短命組件,實時性強且跟應用其它組件少聯(lián)系的組件,我們大可將數(shù)據(jù)流范圍從應用級(redux之類)收窄至組件本身state,這樣讓組件更加single,而我們自行封裝的取數(shù)邏輯(hook)可以在axios,fetch甚至原生xhr上二次封裝,在里面loading狀態(tài)時throw個promise就可以在<Supense>里有延遲效果了

// usage
const AsyncComponentA = () => {
    const { data } = useFetch('api1')  // 自己封裝取數(shù)邏輯
    return (
       <div>{data.whatthe}</div>
    )
}
const AsyncComponentB = () => {
    const { data } = useFetch('api2')  // 自己封裝取數(shù)邏輯
    return (
       <div>{data.whatthe}</div>
    )
}

<Suspense fallback={<Loading />}>
   <AsyncComponentA />
   <AsyncComponentB />
</Suspense>

Suspense和改造過的取數(shù)hook能帶來什么效果

1.loading邏輯和 UI 解耦
2.Suspense可以嵌套使用,聲明方式時加載狀態(tài)順序可控
3.競態(tài)更加可控

參考文獻
1.https://zh-hans.reactjs.org/docs/concurrent-mode-suspense.html#what-if-i-dont-use-relay
2.https://juejin.im/post/5c7d4a785188251b921f4e26#heading-5

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容