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

由于前段時間在領(lǐng)導(dǎo)的“威逼利誘”下,了解和學(xué)習(xí)了下Recoil蔗草,剛開始是比較抗拒的,不過后來慢慢的了解了之后咒精,發(fā)現(xiàn)還是很不錯的镶柱,所以做一個學(xué)習(xí)的筆記和分享模叙。

Recoil最重要的因為它是基于Immutable的數(shù)據(jù)流管理方案歇拆,帶來的可預(yù)測性非常利于調(diào)試和維護:

1.斷點調(diào)試時可預(yù)測范咨,已創(chuàng)建過的值不會突變,與斷點位置也無關(guān)
2.在React框架下組件更新機制單一只有引用變化才觸發(fā)重新渲染输吏,沒有forceUpdate的困擾

上手使用

1.初始化:使用Recoil的狀態(tài)的組件需要用RecoilRoot包裹

    import React from 'react';
     import {
        RecoilRoot,
        atom,
        selector,
        useRecoilState,
        useRecoilValue,
        useSetRecoilState
     } from 'recoil';

     function App() {
        return (
            <RecoilRoot>
                <CharacterCounter />
            </RecoilRoot>
        );
     }

2.定義狀態(tài):不需要集中定義替蛉,可以像Mobx分散在各個地方

   export const nameState = atom({
        key: 'nameState',
        default: 'test'
    });

其中key在recoliRoot中是唯一的拄氯,并且提供一個默認值它浅,默認值可以是靜態(tài)值、函數(shù)艇纺、異步函數(shù)等

3.訂閱和更新狀態(tài):三個常用API

1). useRecoilState:類似useState的一個Hook邮弹,能夠取到Atom的值以及setter函數(shù)
2). useSetRecoilState:只獲取setter函數(shù)蚓聘,如果只是使用了這個函數(shù),狀態(tài)更新并不會引起組件重新渲染
3). useRecoilValue:只獲取狀態(tài)

import { nameState } from './store'
// useRecoilState
const NameInput = () => {
    const [name, setName] = useRecoilState(nameState);
    const onChange = (event) => {
     setName(event.target.value);
    };
    return <>
     <input type="text" value={name} onChange={onChange} />
     <div>Name: {name}</div>
    </>;
}

// useRecoilValue
const SomeOtherComponentWithName = () => {
    const name = useRecoilValue(nameState);
    return <div>{name}</div>;
}

// useSetRecoilState  
const SomeOtherComponentThatSetsName = () => {
    const setName = useSetRecoilState(nameState);
    return <button onClick={() => setName('Jon Doe')}>Set Name</button>;
}

4.派生狀態(tài):與Mobx的computed類似与纽,selector表示一段派生狀態(tài)塘装,提供了get、set蹦肴、分別定義如何賦值,如何取值勺阐,同時其與atom定義的一樣可以使用上述三種API矛双。

const lengthState = selector({
  key: 'lengthState', 
  get: ({get}) => {
    const text = get(nameState);
    return text.length;
  },
});

function NameLength() {
  const length = useRecoilValue(lengthState);
  return <>Name Length: {length}</>;
}

5.異步狀態(tài):基于selector可以實現(xiàn)異步數(shù)據(jù)讀取,即修改get函數(shù)為異步函數(shù)

const userNameQuery = selector({
  key: 'userName',
  get: async ({get}) => {
    const response = await myDBQuery({
      userID: get(currentUserIDState),
    });
    return response.name;
  },
});

function CurrentUserInfo() {
  const userName = useRecoilValue(userNameQuery);
  return <div>{userName}</div>;
}

function MyApp() {
  return (
    <RecoilRoot>
      <ErrorBoundary>
        <React.Suspense fallback={<div>Loading...</div>}>
          <CurrentUserInfo />
        </React.Suspense>
      </ErrorBoundary>
    </RecoilRoot>
  );
}

其中懒闷,異步狀態(tài)可以被Suspense捕獲栈幸,異步過程報錯可以被ErrorBoundary捕獲。
如果不想用Suspense異步阻塞侦镇,可以使用useRecoilValueLoadable在當前組件內(nèi)管理異步狀態(tài)

不足

  • Immutable壓力:API繁多,而且Immutable模式中震捣,對于數(shù)據(jù)流只有讀和寫兩種訴求,但是我們期待讀的含義是蒿赢,UI能夠在訂閱其變化后自然而然Rerender。
    Recoil提供了useRecoilState作為讀寫雙重API壹若,useRecoilValue只是簡化了API皂冰,但是useSetRecoilValue在僅寫不讀的場景下,是不會隨著狀態(tài)變更重新渲染組件的秃流。
    對比useState,他是單組件狀態(tài)管理的場景概说,但Recoil是全局狀態(tài)解決方案嚣伐,讀寫分離的場景下糖赔,對于只寫的組件很有必要脫離對數(shù)據(jù)的訂閱實現(xiàn)性能最大化轩端。
  • 條件訪問數(shù)據(jù):因為Hooks的通病放典,無法寫在條件語句中船万,所以要利用 Hooks 獲取一個帶有條件判斷的數(shù)據(jù)時,必須回到 selector 模式耿导。
    從useRecoilState以及selector來看,相當于Recoil對useContext和useMemo的封裝舱呻。

收獲

盡管短時間內(nèi)我們不會在項目上Recoil,但是它帶給我們的絕不只是上述的用法芥驳,在狀態(tài)管理上茬高,我們或許可以思考新的出發(fā)點:

  • 讀與寫分離兆旬,做到最優(yōu)按需渲染
  • 派生的值必須嚴格緩存怎栽,并在命中緩存時引用保證嚴格相等
  • 原子存儲的數(shù)據(jù)相互無關(guān)聯(lián)宿饱,所有關(guān)聯(lián)的數(shù)據(jù)都使用派生值方式推導(dǎo)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谬以,一起剝皮案震驚了整個濱河市由桌,隨后出現(xiàn)的幾起案子为黎,更是在濱河造成了極大的恐慌行您,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件片橡,死亡現(xiàn)場離奇詭異淮野,居然都是意外死亡吹泡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門洞难,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人队贱,你說我怎么就攤上這事潭袱。” “怎么了屯换?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵彤悔,是天一觀的道長。 經(jīng)常有香客問我晕窑,道長,這世上最難降的妖魔是什么敞斋? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮挫鸽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘丢郊。我一直安慰自己医咨,他們只是感情好,可當我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布干茉。 她就那樣靜靜地躺著很泊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪委造。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天枫虏,我揣著相機與錄音爬虱,去河邊找鬼。 笑死跑筝,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的回俐。 我是一名探鬼主播稀并,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼碘举!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起耕皮,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎粱年,沒想到半個月后罚拟,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體台诗,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡拉队,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年阻逮,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片事哭。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡瓜富,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出食呻,到底是詐尸還是另有隱情澎现,我是刑警寧澤,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布干旧,位于F島的核電站妹蔽,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏胳岂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一掌测、第九天 我趴在偏房一處隱蔽的房頂上張望产园。 院中可真熱鬧夜郁,春花似錦粘勒、人聲如沸竞端。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至暂刘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谣拣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工拔鹰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留贵涵,地道東北人。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓瓷马,卻偏偏與公主長得像,于是被迫代替她去往敵國和親欧聘。 傳聞我的和親對象是個殘疾皇子端盆,可洞房花燭夜當晚...
    茶點故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內(nèi)容