入門
如果你準備好了,那麼請先創建一個新的 React App,我們將使用它來開始我們的實踐:
npx create-react-app react-state-examples
cd react-state-examples
無論何時何地,使用 start 命令啟動你的命令。
npm start
Recoil
Recoil Docs[6]
代碼行數:30
我最喜歡 Recoil 的點是因為它基於 Hooks 的 API 以及它的直觀性。
與其他一些庫相比,我想說 Recoil 的和 API 比大多數庫更容易。
Recoil 實踐
開始使用Recoil前,先安裝依賴:
npm install recoil
接下來,將 RecoilRoot 添加到 App 程序的根/入口點:
import App from './App'
import { RecoilRoot } from 'recoil'
export default function Main() {
return (
);
}
下一步,要創建一些狀態,我們將使用來自Recoil 的 atom 並設置key和一些初始狀態:
import { atom } from 'recoil'
const notesState = atom({
key: 'notesState', // unique ID (with respect to other atoms/selectors)
default: [], // default value (aka initial state)
});
現在,你可以在你app的任何位置使用來自 Recoil 的useRecoilState。這是使用 Recoil 實現的筆記 App:
import React, { useState } from 'react';
import { RecoilRoot, atom, useRecoilState } from 'recoil';
const notesState = atom({
key: 'notesState', // unique ID (with respect to other atoms/selectors)
default: [], // default value (aka initial state)
});
export default function Main() {
return (
);
}
function App() {
const [notes, setNotes] = useRecoilState(notesState);
const [input, setInput] = useState('')
function createNote() {
const notesArray = [...notes, input]
setNotes(notesArray)
setInput('')
}
return (
My notes app
setInput(e.target.value)} />
{ notes.map(note =>
Note: {note}
) }) }
);
}
Recoil selectors
來自文檔
selectors 用於計算基於 state 的派生屬性。這能讓我們避免冗餘 state,通常無需使用 reducers 來保持狀態同步和有效。相反,最小狀態集存儲在 atoms 中。
使用 Recoil selectors,你可以根據 state 計算派生屬性,例如,可能是已過濾的待辦事項數組(在todo app 中)或已發貨的訂單數組(在電子商務應用程序中):
import { selector, useRecoilValue } from 'recoil'
const completedTodosState = selector({
key: 'todosState',
get: ({get}) => {
const todos = get(todosState)
return todos.filter(todo => todo.completed)
}
})
const completedTodos = useRecoilValue(completedTodosState)
結論
recoil 文檔說:"Recoil 是一個用於 React 狀態管理的實驗性使用工具集。" 當我決定在生產環境中使用庫時,聽到"實驗性"可能會非常擔心,所以至少在此刻,我不確定我現在對使用 Recoil 的感覺如何 。
Recoil 很棒,我會為我的下一個 app 使用上它,但是擔心實驗性屬性,因此我將密切關注它,但現在不將它用於生產中。
Mobx
MobX React Lite Docs[7]
代碼行數: 30
因為我在使用 Redux 之後使用了MobX React, 所以它一直是我最喜歡的管理 React 狀態庫之一。多年來,兩者之間的明顯差異,但是對我而言我不會改變我的選擇。
MobX React 現在有一個輕量級版本(MobX React Lite),這個版本專門針對函數組件而誕生,它的有點是速度更快,更小。
MobX 具有可觀察者和觀察者的概念,然而可觀察的API有所改變,那就是不必指定希望被觀察的每個項,而是可以使用 makeAutoObservable 來為你處理所有事情。
如果你希望數據是響應的並且需要修改 store ,則可以用observer來包裝組件。
MobX 實踐
開始使用Mobx前,先安裝依賴:
npm install mobx mobx-react-lite
該應用的狀態已在 Store 中創建和管理。
我們應用的 store 如下所示:
import { makeAutoObservable } from 'mobx'
class NoteStore {
notes = []
createNote(note) {
this.notes = [...this.notes, note]
}
constructor() {
/* makes all data in store observable, replaces @observable */
makeAutoObservable(this)
}
}
const Notes = new NoteStore()
然後,我們可以導入notes,並在 app 中的任何位置使用它們。要使組件是可觀察修改,需要將其包裝在observer中:
import { observer } from 'mobx-react-lite'
import { notes } from './NoteStore'
const App = observer(() =>
{notes[0]|| "No notes"}
)讓我們看看它們如何一起運行的:
import React, { useState } from 'react'
import { observer } from "mobx-react-lite"
import { makeAutoObservable } from 'mobx'
class NoteStore {
notes = []
createNote(note) {
this.notes = [...this.notes, note]
}
constructor() {
makeAutoObservable(this)
}
}
const Notes = new NoteStore()
const App = observer(() => {
const [input, setInput] = useState('')
const { notes } = Notes
function onCreateNote() {
Notes.createNote(input)
setInput('')
}
return (
My notes app
setInput(e.target.value)} />
{ notes.map(note =>
Note: {note}
) }) }
)
})
export default App
總結
MobX 已經誕生了一段時間,它很好用。與許多其他公司一樣,我在企業公司的大量線上應用中使用了它。
最近再次使用它之後的感受是,與其他一些庫相比,我覺得文檔略有不足。我會自己再嘗試一下,然後再做決定。
XState
XState Docs[8]
代碼行數:44
XState 試圖解決現代UI複雜性的問題,並且依賴於有限狀態機[9]的思想和實現。
XState 是由 David Khourshid[10], 創建的,自發布以來,我就看到過很多關於它的討論,所以我一直在觀望。這是在寫本文之前唯一不熟悉的庫。
在使用之後,我可以肯定地說它的實現方式是與其他庫截然不同的。它的複雜性比其他任何一種都要高,但是關於狀態如何工作的思維模型確實很 cool 而且對於提高能力很有幫助,在用它構建一些 demo app 之後,讓我感到它很精妙。
要了解有關 XState 試圖解決的問題的更多信息,請查看David Khourshid的這段視頻[11]或我也發現有趣的帖子[12]。
XState 在這裡的使用不是特別好,因為它更適合在更復雜的狀態下使用,但是這個簡短的介紹至少可以希望為你提供一個選擇,以幫助你全面瞭解其工作原理。
XState實踐
要開始使用XState,請安裝這些庫:
npm install xstate @xstate/react
要創建machine,請使用xstate中的Machine實用程序。這是我們將用於 Notes app 的machine:
import { Machine } from 'xstate'
const notesMachine = Machine({
id: 'notes',
initial: 'ready',
context: {
notes: [],
note: ''
},
states: {
ready: {},
},
on: {
"CHANGE": {
actions: [
assign({
note: (_, event) => event.value
})
]
},
"CREATE_NOTE": {
actions: [
assign({
note: "",
notes: context => [...context.notes, context.note]
})
]
}
}
})
我們將使用的數據存儲在 context 中。在這裡,我們有一個 notes 列表 和一個 input 輸入框。有兩種操作,一種用於創建 note(CREATE_NOTE),另一種用於設置 input(CHANGE)。
整個示例:
import React from 'react'
import { useService } from '@xstate/react'
import { Machine, assign, interpret } from 'xstate'
const notesMachine = Machine({
id: 'notes',
initial: 'ready',
context: {
notes: [],
note: ''
},
states: {
ready: {},
},
on: {
"CHANGE": {
actions: [
assign({
note: (_, event) => event.value
})
]
},
"CREATE_NOTE": {
actions: [
assign({
note: "",
notes: context => [...context.notes, context.note]
})
]
}
}
})
const service = interpret(notesMachine).start()
export default function App() {
const [state, send] = useService(service)
const { context: { note, notes} } = state
return (
My notes app
send({ type: 'CHANGE', value: e.target.value})} />
{ notes.map(note =>
Note: {note}
) }) }
)
}
要在應用中修改狀態,我們使用 xstate-react 中的 useService hooks。
總結
XState 就像勞斯萊斯 或者說 狀態管理的瑞士軍刀。可以做很多事情,但是所有功能都帶來額外的複雜性。
我希望將來能更好地學習和理解它,這樣我就可以將它應用到 AWS 的相關問題和參考它的架構,但是對於小型項目,我認為這可能它太過龐大。
Redux
React Redux docs[13]
代碼行數:33
Redux 是整個 React 生態系統中最早,最成功的狀態管理庫之一。我已經在許多項目中使用過Redux,如今它依然很強大。
新的 Redux Hooks API 使 redux 使用起來不再那麼麻煩,而且使用起來也更容易。
Redux Toolkit 還改進了 Redux,並大大降低了學習曲線。
Redux 實踐
開始使用Redux前,先安裝依賴:
npm install @reduxjs-toolkit react-redux
要使用 Redux,您需要創建和配置以下內容:
- A store
- Reducers
- A provider
為了幫助解釋所有這些工作原理,我在實現 Redux 中的 Notes app 的代碼中做了註釋:
import React, { useState } from 'react'
import { Provider, useDispatch, useSelector } from 'react-redux'
import { configureStore, createReducer, combineReducers } from '@reduxjs/toolkit'
function App() {
const [input, setInput] = useState('')
/* useSelector 允許你檢索你想使用的狀態,在我們的例子中是notes數組。 */
const notes = useSelector(state => state.notes)
/* dispatch 允許我們向 store 發送更新信息 */
const dispatch = useDispatch()
function onCreateNote() {
dispatch({ type: 'CREATE_NOTE', note: input })
setInput('')
}
return (
My notes app
setInput(e.target.value)} />
{ notes.map(note =>
Note: {note}
) }) }
);
}
/* 在這裡,我們創建了一個 reducer,它將在`CREATE_NOTE`動作被觸發時更新note數組。 */
const notesReducer = createReducer([], {
'CREATE_NOTE': (state, action) => [...state, action.note]
})
/* Here we create the store using the reducers in the app */
const reducers = combineReducers({ notes: notesReducer })
const store = configureStore({ reducer: reducers })
function Main() {
return (
/* 在這裡,我們使用app中的reducer來創建store。 */
)
}
export default Main
總結
如果你正在尋找一個具有龐大社區、大量文檔以及大量問答的庫,那麼Redux是一個非常靠譜的選擇。因為它已誕生了很長時間,你只要在 Google 搜索,或多或少都能找到一些相關的答案。
在使用異步操作(例如數據獲取)時,通常需要添加其他中間件,這會增加它的成本和複雜性。
對我來說,Redux 起初很難學習。一旦我熟悉了框架,就可以很容易地使用和理解它。過去,對於新開發人員而言,有時會感到不知所措,但是隨著 Redux Hooks 和 Redux Toolkit 的改進,學習過程變得容易得多,我仍然強烈建議 Redux 作為前置的選擇。
Context
Context docs[14]
代碼行數: 31
context 的優點在於,不需要安裝和依賴其他庫,它是 React 的一部分。
使用 context 非常簡單,當你嘗試管理大量不同的 context 值時,問題通常會出現在一些大或者複雜的應用程序中,因此你通常必須構建自己的抽象來自己管理這些情況。
Context 實踐
要創建和使用 context ,請直接從React導入鉤子。下面是它的工作原理:
/* 1. Import the context hooks */
import React, { useState, createContext, useContext } from 'react';
/* 2. Create a piece of context */
const NotesContext = createContext();
/* 3. Set the context using a provider */
/* 4. Use the context */
const { notes } = useContext(NotesContext);
全部代碼
import React, { useState, createContext, useContext } from 'react';
const NotesContext = createContext();
export default function Main() {
const [notes, setNotes] = useState([])
function createNote(note) {
const notesArray = [...notes, note]
setNotes(notesArray)
}
return (
);
}
function App() {
const { notes, createNote } = useContext(NotesContext);
const [input, setInput] = useState('')
function onCreateNote() {
createNote(input)
setInput('')
}
return (
My notes app
setInput(e.target.value)} />
{ notes.map(note =>
Note: {note}
) }) }
);
}
總結
context 是一種管理 app 狀態的真正可靠且直接的方法。它的API可能不如其他一些庫那麼好,但是如果你瞭解如何使用它,並且可以在你的 app 中使用它創建正確的數據抽象,那麼選擇 context 來管理你的全局狀態就不會錯。