核心概念
概述
反沖作用讓您可以建立資料流程圖,從原子(共用狀態)透過選擇子(純函數)流入 React 元件中。原子是元件可以訂閱的狀態單位。選擇子可以同步或異步轉換此狀態。
原子
原子是狀態單位。它們可更新且可訂閱:當原子更新時,每個已訂閱的元件都會重新以新值渲染。它們也可以在執行時期建立。原子可用來取代 React 本機元件狀態。如果同一個原子從多個元件中使用,所有這些元件都會分享其狀態。
使用 atom
函數來建立原子
const fontSizeState = atom({
key: 'fontSizeState',
default: 14,
});
原子需要一個唯一的金鑰,用於調試、持久儲存以及某些進階 API,可以讓您看到所有原子的對應表。如果兩個原子有相同金鑰,則會產生錯誤,因此請確保它們是全球唯一的。與 React 元件狀態類似,它們也有預設值。
要從元件讀取和寫入原子,我們使用名為 useRecoilState
的鉤子。它就像 React 的 useState
,但現在共用狀態可以讓元件使用
function FontButton() {
const [fontSize, setFontSize] = useRecoilState(fontSizeState);
return (
<button onClick={() => setFontSize((size) => size + 1)} style={{fontSize}}>
Click to Enlarge
</button>
);
}
按一下按鈕會將按鈕的字型大小增加 1。但現在某些其他元件也可以使用相同的字型大小
function Text() {
const [fontSize, setFontSize] = useRecoilState(fontSizeState);
return <p style={{fontSize}}>This text will increase in size too.</p>;
}
選擇子
選擇器是一個純粹接受原子或其他選擇器作為輸入的函數。當這些上游原子或選擇器更新時,選擇器函數將重新評估。組件可以像原子那樣訂閱選擇器,然後在選擇器改變時重新呈現。
選擇器用於計算基於狀態的衍生數據。這讓我們可以避免狀態冗餘,因為是最小的狀態集合儲存在原子中,而其他所有內容都作為該最小狀態的函數有效率地計算。由於選擇器追蹤哪些組件需要它們,以及它們依賴的狀態,因此它們使這種函式方法非常有效率。
從組件的角度來看,選擇器和原子有相同的介面,因此可以互相替換。
使用 selector
函數定義選擇器
const fontSizeLabelState = selector({
key: 'fontSizeLabelState',
get: ({get}) => {
const fontSize = get(fontSizeState);
const unit = 'px';
return `${fontSize}${unit}`;
},
});
get
屬性是要計算的函數。它可以使用傳遞給它的 get
參數存取原子和其他選擇器的值。每當它存取其他原子或選擇器時,都會建立一個依賴關係,使更新其他原子或選擇器會導致重新計算這個原子或選擇器。
在此 fontSizeLabelState
範例中,選擇器有一個依賴項:fontSizeState
原子。從概念上來說,fontSizeLabelState
選擇器的作用類似於一個純函數,輸入 fontSizeState
並輸出已格式化的字體大小標籤。
可以使用 useRecoilValue()
讀取選擇器,它將原子或選擇器作為參數,並傳回對應值。我們不使用 useRecoilState()
,因為 fontSizeLabelState
選擇器不可寫(有關可寫選擇器的更多資訊,請參閱 選擇器 API 參考)
function FontButton() {
const [fontSize, setFontSize] = useRecoilState(fontSizeState);
const fontSizeLabel = useRecoilValue(fontSizeLabelState);
return (
<>
<div>Current font size: {fontSizeLabel}</div>
<button onClick={() => setFontSize(fontSize + 1)} style={{fontSize}}>
Click to Enlarge
</button>
</>
);
}
現在按一下按鈕將執行兩件事:它會增加按鈕的字體大小,同時也會更新字體大小標籤以反映目前的字體大小。