自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Facebook新一代React狀態(tài)管理庫Recoil

開發(fā) 前端
Recoil 現(xiàn)在還處于實(shí)驗(yàn)階段,現(xiàn)在已經(jīng)在 Facebook 一些內(nèi)部產(chǎn)品中用于生產(chǎn)環(huán)境。畢竟是官方推出的狀態(tài)管理框架,之前沒時間仔細(xì)研究,借著國慶期間看了看,給大家分享一下。

[[345158]]

在 React Europe 2020 Conference 上, Facebook 軟件工程師 Dave McCabe 介紹了一個新的狀態(tài)管理庫 Recoil。

Recoil 現(xiàn)在還處于實(shí)驗(yàn)階段,現(xiàn)在已經(jīng)在 Facebook 一些內(nèi)部產(chǎn)品中用于生產(chǎn)環(huán)境。畢竟是官方推出的狀態(tài)管理框架,之前沒時間仔細(xì)研究,借著國慶期間看了看,給大家分享一下。

State 和 Context 的問題

假設(shè)我們有下面一個場景:有 List 和 Canvas 兩個組件,List 中一個節(jié)點(diǎn)更新后,Canvas 中的節(jié)點(diǎn)也對應(yīng)更新。

最常規(guī)則做法是將一個 state 通過父組件分發(fā)給 List 和 Canvas 兩個組件,顯然這樣的話每次 state 改變后 所有節(jié)點(diǎn)都會全量更新。

當(dāng)然,我們還可以使用 Context API,我們將節(jié)點(diǎn)的狀態(tài)存在一個 Context 內(nèi),只要 Provider 中的 props 發(fā)生改變, Provider 的所有后代使用者都會重新渲染。

為了避免全量渲染的問題,我們可以把每個子節(jié)點(diǎn)存儲在單獨(dú)的 Context 中,這樣每多一個節(jié)點(diǎn)就要增加一層 Provider。

但是,如果子節(jié)點(diǎn)是動態(tài)增加的呢?我們還需要去動態(tài)增加 Provider ,這會讓整個樹再次重新渲染,顯然也是不符合預(yù)期的。引入 Recoil

Recoil 本身就是為了解決 React 全局?jǐn)?shù)據(jù)流管理的問題,采用分散管理原子狀態(tài)的設(shè)計模式。

Recoil 提出了一個新的狀態(tài)管理單位 Atom,它是可更新和可訂閱的,當(dāng)一個 Atom 被更新時,每個被訂閱的組件都會用新的值來重新渲染。如果從多個組件中使用同一個 Atom ,所有這些組件都會共享它們的狀態(tài)。

你可以把 Atom 想象為為一組 state 的集合,改變一個 Atom 只會渲染特定的子組件,并不會讓整個父組件重新渲染。

用 Redux 或 Mobx 不可以嗎?

[[345163]]

因?yàn)?React 本身提供的 state 狀態(tài)在跨組件狀態(tài)共享上非??嚯y,所以我們在開發(fā)時一般借助一些其他的庫如 Redux、Mobx 來幫助我們管理狀態(tài)。這些庫目前正被廣泛使用,我們也并沒有遇到什么大問題,那么 Facebook 為什么還要推出一款新的狀態(tài)管理框架呢?

使用 Redux、Mobx 當(dāng)然可以,并沒有什么問題,主要原因是它們本身并不是 React 庫,我們是借助這些庫的能力來實(shí)現(xiàn)狀態(tài)管理。像 Redux 它本身雖然提供了強(qiáng)大的狀態(tài)管理能力,但是使用的成本非常高,你還需要編寫大量冗長的代碼,另外像異步處理或緩存計算也不是這些庫本身的能力,甚至需要借助其他的外部庫。

并且,它們并不能訪問 React 內(nèi)部的調(diào)度程序,而 Recoil 在后臺使用 React 本身的狀態(tài),在未來還能提供并發(fā)模式這樣的能力。

基礎(chǔ)使用

初始化

使用 recoil 狀態(tài)的組件需要使用 RecoilRoot 包裹起來: 

  1. import React from 'react';  
  2. import {  
  3.   RecoilRoot,  
  4.   atom,  
  5.   selector,  
  6.   useRecoilState,  
  7.   useRecoilValue,  
  8.   useSetRecoilState  
  9. } from 'recoil';  
  10. function App() {  
  11.   return (  
  12.     <RecoilRoot>  
  13.       <CharacterCounter />  
  14.     </RecoilRoot>  
  15.   );  

定義狀態(tài)

上面我們已經(jīng)提到了 Atom 的概念, Atom 是一種新的狀態(tài),但是和傳統(tǒng)的 state 不同,它可以被任何組件訂閱,當(dāng)一個 Atom 被更新時,每個被訂閱的組件都會用新的值來重新渲染。

首先我們來定義一個 Atom: 

  1. export const nameState = atom({  
  2.   key: 'nameState', 
  3.   default: 'ConardLi'  
  4. }); 

這種方式意味著你不需要像 Redux 那樣集中定義狀態(tài),可以像 Mobx 一樣將數(shù)據(jù)分散定義在任何地方。

要創(chuàng)建一個 Atom ,必須要提供一個 key ,其必須在 RecoilRoot 作用域中是唯一的,并且要提供一個默認(rèn)值,默認(rèn)值可以是一個靜態(tài)值、函數(shù)甚至可以是一個異步函數(shù)。

訂閱和更新狀態(tài)

Recoil 采用 Hooks 方式訂閱和更新狀態(tài),常用的是下面三個 API:

  •  useRecoilState:類似 useState 的一個 Hook,可以取到 atom 的值以及 setter 函
  •  useSetRecoilState:只獲取 setter 函數(shù),如果只使用了這個函數(shù),狀態(tài)變化不會導(dǎo)致組件重新渲染
  •  useRecoilValue:只獲取狀態(tài) 
  1. import { nameState } from './store'  
  2. // useRecoilState  
  3. const NameInput = () => {  
  4.   const [name, setName] = useRecoilState(nameState);  
  5.   const onChange = (event) => {  
  6.    setName(event.target.value);  
  7.   };  
  8.   return <>  
  9.    <input type="text" value={name} onChange={onChange} />  
  10.    <div>Name: {name}</div>  
  11.   </> 
  12.  
  13. // useRecoilValue  
  14. const SomeOtherComponentWithName = () => {  
  15.   const name = useRecoilValue(nameState);  
  16.   return <div>{name}</div> 
  17.  
  18. // useSetRecoilState   
  19. const SomeOtherComponentThatSetsName = () => {  
  20.   const setName = useSetRecoilState(nameState);  
  21.   return <button onClick={() => setName('Jon Doe')}>Set Name</button> 

派生狀態(tài)

selector 表示一段派生狀態(tài),它使我們能夠建立依賴于其他 atom 的狀態(tài)。它有一個強(qiáng)制性的 get 函數(shù),其作用與 redux 的 reselect 或 MobX 的 @computed 類似。 

  1. const lengthState = selector({  
  2.   key: 'lengthState',   
  3.   get: ({get}) => {  
  4.     const text = get(nameState);  
  5.     return text.length;  
  6.   },  
  7. });  
  8. function NameLength() {  
  9.   const length = useRecoilValue(charLengthState);  
  10.   return <>Name Length: {length}</> 

selector 是一個純函數(shù):對于給定的一組輸入,它們應(yīng)始終產(chǎn)生相同的結(jié)果(至少在應(yīng)用程序的生命周期內(nèi))。這一點(diǎn)很重要,因?yàn)檫x擇器可能會執(zhí)行一次或多次,可能會重新啟動并可能會被緩存。

異步狀態(tài)

Recoil 提供了通過數(shù)據(jù)流圖將狀態(tài)和派生狀態(tài)映射到 React 組件的方法。真正強(qiáng)大的功能是圖中的函數(shù)也可以是異步的。這使得我們可以在異步 React 組件渲染函數(shù)中輕松使用異步函數(shù)。使用 Recoil ,你可以在選擇器的數(shù)據(jù)流圖中無縫地混合同步和異步功能。只需從選擇器 get 回調(diào)中返回 Promise ,而不是返回值本身。

例如下面的例子,如果用戶名存儲在我們需要查詢的某個數(shù)據(jù)庫中,那么我們要做的就是返回一個 Promise 或使用一個 async 函數(shù)。如果 userID 發(fā)生更改,就會自動重新執(zhí)行新查詢。結(jié)果會被緩存,所以查詢將僅對每個唯一輸入執(zhí)行一次(所以一定要保證 selector 純函數(shù)的特性,否則緩存的結(jié)果將會和最新的值不一致)。 

  1. const userNameQuery = selector({  
  2.   key: 'userName',  
  3.   get: async ({get}) => {  
  4.     const response = await myDBQuery({  
  5.       userID: get(currentUserIDState),  
  6.     });  
  7.     return response.name;  
  8.   },  
  9. });  
  10. function CurrentUserInfo() {  
  11.   const userName = useRecoilValue(userNameQuery);  
  12.   return <div>{userName}</div> 

Recoil 推薦使用 Suspense,Suspense 將會捕獲所有異步狀態(tài),另外配合 ErrorBoundary 來進(jìn)行錯誤捕獲: 

  1. function MyApp() {  
  2.   return (  
  3.     <RecoilRoot>  
  4.       <ErrorBoundary>  
  5.         <React.Suspense fallback={<div>Loading...</div>}>  
  6.           <CurrentUserInfo />  
  7.         </React.Suspense>  
  8.       </ErrorBoundary>  
  9.     </RecoilRoot>  
  10.   );  

總結(jié)

Recoil 推崇的是分散式的狀態(tài)管理,這個模式很類似于 Mobx,使用起來也感覺有點(diǎn)像 observable + computed 的模式,但是其 API 以及核心思想設(shè)計的又沒有  Mobx 一樣簡潔易懂,反而有點(diǎn)復(fù)雜,對于新手上手起來會有一定成本。

在使用方式上完全擁抱了函數(shù)式的 Hooks 使用方式,并沒有提供 Componnent 的使用方式,目前使用原生的 Hooks API 我們也能實(shí)現(xiàn)狀態(tài)管理,我們也可以使用 useMemo 創(chuàng)造出派生狀態(tài),Recoil 的 useRecoilState 以及 selector 也比較像是對 useContext、useMemo 的封裝。

但是畢竟是 Facebook 官方推出的狀態(tài)管理框架,其主打的是高性能以及可以利用 React 內(nèi)部的調(diào)度機(jī)制,包括其承諾即將會支持的并發(fā)模式,這一點(diǎn)還是非常值得期待的。

另外,其本身的分散管理原子狀態(tài)的模式、讀寫分離、按需渲染、派生緩存等思想還是非常值得一學(xué)的。 

 

責(zé)任編輯:龐桂玉 來源: 前端大全
相關(guān)推薦

2020-11-13 15:40:18

React前端Recoil

2022-05-23 08:59:02

piniavue插件

2021-08-17 11:16:27

NVIDIA

2012-07-02 10:36:19

菲亞特

2022-03-10 16:01:29

Playwright開源

2022-05-09 19:19:36

Pnpm管理工具

2021-08-14 08:45:27

React開發(fā)應(yīng)用程序

2022-02-07 23:03:07

Python工具管理庫

2016-01-26 11:58:12

2013-01-04 16:15:08

微軟ERPDynamics AX

2017-12-18 15:48:38

Facebook OpR

2011-03-31 17:49:51

微軟嵌入式WindowsEmbe

2009-03-11 13:02:20

存儲虛擬化數(shù)據(jù)中心

2010-06-17 16:54:49

新一代Hotmail

2009-09-02 16:10:40

ADSL技術(shù)

2018-06-01 15:18:43

LinuxOrbital App開源

2017-10-19 16:21:02

SCM存儲技術(shù)

2010-05-05 18:05:00

新一代數(shù)據(jù)中心

2016-12-11 10:35:52

2009-10-13 10:04:51

醫(yī)院協(xié)同呼叫中心
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號