在 React 中,似乎有无数种处理状态管理的方法。想要了解各种库,去比较它们之间的如何选择以及它们如何原作都是一件令人头疼的事情。
当我学习一些新东西时,喜欢去比较那些实现相同功能的库,这有助于我理解各种库之间的差别,并且能够形成一个自己在构建应用的时候如何选择使用它们的思维模型。
在本文中,我将一一介绍如何在 React App 中使用 5 种最流行的库/APIS(使用最现代和最新版本的库)如何在 React App程序中使用全局状态管理,并且达到一样的效果。
我还将试着解释它们之间的差异,本文以 概述 - 代码 - 结论的方式讲解。
为了演示 APIS,我们将使用这些库来做一个如何创建和展示笔记
的应用。
如果你准备好了,那么请先创建一个新的 React App,我们将使用它来开始我们的实践:
npx create-react-app react-state-examples
cd react-state-examples
无论何时何地,使用 start
命令启动你的命令。
npm start
Recoil Docs[6]
代码行数:30
我最喜欢 Recoil 的点是因为它基于 Hooks 的 API 以及它的直观性。
与其他一些库相比,我想说 Recoil 的和 API 比大多数库更容易。
开始使用Recoil
前,先安装依赖:
npm install recoil
接下来,将 RecoilRoot
添加到 App 程序的根/入口点:
import App from './App'
import { RecoilRoot } from 'recoil'
export default function Main() {
return (
<RecoilRoot>
<App />
</RecoilRoot>
);
}
下一步,要创建一些状态,我们将使用来自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 (
<RecoilRoot>
<App />
</RecoilRoot>
);
}
function App() {
const [notes, setNotes] = useRecoilState(notesState);
const [input, setInput] = useState('')
function createNote() {
const notesArray = [...notes, input]
setNotes(notesArray)
setInput('')
}
return (
<div>
<h1>My notes app</h1>
<button onClick={createNote}>Create Note</button>
<input value={input} onChange={e => setInput(e.target.value)} />
{ notes.map(note => <p key={note}>Note: {note}</p>) }
</div>
);
}
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 React Lite Docs[7]
代码行数: 30
因为我在使用 Redux 之后使用了MobX React, 所以它一直是我最喜欢的管理 React 状态库之一。多年来,两者之间的明显差异,但是对我而言我不会改变我的选择。
MobX React 现在有一个轻量级版本(MobX React Lite),这个版本专门针对函数组件而诞生,它的有点是速度更快,更小。
MobX 具有可观察者和观察者的概念,然而可观察的API有所改变,那就是不必指定希望被观察的每个项,而是可以使用 makeAutoObservable
来为你处理所有事情。
如果你希望数据是响应的并且需要修改 store ,则可以用observer
来包装组件。
开始使用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(() => <h1>{notes[0]|| "No notes"}</h1>)
让我们看看它们如何一起运行的:
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 (
<div>
<h1>My notes app</h1>
<button onClick={onCreateNote}>Create Note</button>
<input value={input} onChange={e => setInput(e.target.value)} />
{ notes.map(note => <p key={note}>Note: {note}</p>) }
</div>
)
})
export default App
MobX 已经诞生了一段时间,它很好用。与许多其他公司一样,我在企业公司的大量线上应用中使用了它。
最近再次使用它之后的感受是,与其他一些库相比,我觉得文档略有不足。我会自己再尝试一下,然后再做决定。
XState Docs[8]
代码行数:44
XState 试图解决现代UI复杂性的问题,并且依赖于有限状态机[9]的思想和实现。
XState 是由 David Khourshid[10], 创建的,自发布以来,我就看到过很多关于它的讨论,所以我一直在观望。这是在写本文之前唯一不熟悉的库。
在使用之后,我可以肯定地说它的实现方式是与其他库截然不同的。它的复杂性比其他任何一种都要高,但是关于状态如何工作的思维模型确实很 cool 而且对于提高能力很有帮助,在用它构建一些 demo app 之后,让我感到它很精妙。
要了解有关 XState 试图解决的问题的更多信息,请查看David Khourshid的这段视频[11]或我也发现有趣的帖子[12]。
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 (
<div>
<h1>My notes app</h1>
<button onClick={() => send({ type: 'CREATE_NOTE' })}>Create Note</button>
<input value={note} onChange={e => send({ type: 'CHANGE', value: e.target.value})} />
{ notes.map(note => <p key={note}>Note: {note}</p>) }
</div>
)
}
要在应用中修改状态,我们使用 xstate-react
中的 useService hooks。
XState
就像劳斯莱斯 或者说 状态管理的瑞士军刀。可以做很多事情,但是所有功能都带来额外的复杂性。
我希望将来能更好地学习和理解它,这样我就可以将它应用到 AWS 的相关问题和参考它的架构,但是对于小型项目,我认为这可能它太过庞大。
React Redux docs[13]
代码行数:33
Redux 是整个 React 生态系统中最早,最成功的状态管理库之一。我已经在许多项目中使用过Redux,如今它依然很强大。
新的 Redux Hooks API 使 redux 使用起来不再那么麻烦,而且使用起来也更容易。
Redux Toolkit 还改进了 Redux,并大大降低了学习曲线。
开始使用Redux
前,先安装依赖:
npm install @reduxjs-toolkit react-redux
要使用 Redux,您需要创建和配置以下内容:
为了帮助解释所有这些工作原理,我在实现 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 (
<div>
<h1>My notes app</h1>
<button onClick={onCreateNote}>Create Note</button>
<input value={input} onChange={e => setInput(e.target.value)} />
{ notes.map(note => <p key={note}>Note: {note}</p>) }
</div>
);
}
/* 在这里,我们创建了一个 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。 */
<Provider store={store}>
<App />
</Provider>
)
}
export default Main
如果你正在寻找一个具有庞大社区、大量文档以及大量问答的库,那么Redux是一个非常靠谱的选择。因为它已诞生了很长时间,你只要在 Google 搜索,或多或少都能找到一些相关的答案。
在使用异步操作(例如数据获取)时,通常需要添加其他中间件,这会增加它的成本和复杂性。
对我来说,Redux 起初很难学习。一旦我熟悉了框架,就可以很容易地使用和理解它。过去,对于新开发人员而言,有时会感到不知所措,但是随着 Redux Hooks 和 Redux Toolkit 的改进,学习过程变得容易得多,我仍然强烈建议 Redux 作为前置的选择。
Context docs[14]
代码行数: 31
context 的优点在于,不需要安装和依赖其他库,它是 React 的一部分。
使用 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 */
<NotesContext.Provider value={{ notes: ['note1', 'note2'] }}>
<App />
</NotesContext.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 (
<NotesContext.Provider value={{ notes, createNote }}>
<App />
</NotesContext.Provider>
);
}
function App() {
const { notes, createNote } = useContext(NotesContext);
const [input, setInput] = useState('')
function onCreateNote() {
createNote(input)
setInput('')
}
return (
<div>
<h1>My notes app</h1>
<button onClick={onCreateNote}>Create Note</button>
<input value={input} onChange={e => setInput(e.target.value)} />
{ notes.map(note => <p key={note}>Note: {note}</p>) }
</div>
);
}
context 是一种管理 app 状态的真正可靠且直接的方法。它的API可能不如其他一些库那么好,但是如果你了解如何使用它,并且可以在你的 app 中使用它创建正确的数据抽象,那么选择 context 来管理你的全局状态就不会错。
[1]Recoil: https://dev.to/dabit3/react-state-6-ways-2bem?utm_source=digest_mailer&utm_medium=email&utm_campaign=digest_email#recoil
[2]MobX: https://dev.to/dabit3/react-state-6-ways-2bem?utm_source=digest_mailer&utm_medium=email&utm_campaign=digest_email#mobx
[3]XState: https://dev.to/dabit3/react-state-6-ways-2bem?utm_source=digest_mailer&utm_medium=email&utm_campaign=digest_email#xstate
[4]Redux (with hooks): https://dev.to/dabit3/react-state-6-ways-2bem?utm_source=digest_mailer&utm_medium=email&utm_campaign=digest_email#redux
[5]Context: https://dev.to/dabit3/react-state-6-ways-2bem?utm_source=digest_mailer&utm_medium=email&utm_campaign=digest_email#context
[6]Recoil Docs: https://recoiljs.org/
[7]MobX React Lite Docs: https://github.com/mobxjs/mobx-react-lite
[8]XState Docs: https://xstate.js.org/docs/packages/xstate-react/
[9]有限状态机: https://en.wikipedia.org/wiki/Finite-state_machine
[10]David Khourshid: https://twitter.com/DavidKPiano
[11]这段视频: https://www.youtube.com/watch?v=RqTxtOXcv8Y
[12]帖子: https://dev.to/hectorleiva/how-writing-state-machines-made-me-feel-like-a-programmer-2ndc
[13]React Redux docs: https://react-redux.js.org/
[14]Context docs: https://reactjs.org/docs/hooks-reference.html#usecontext
本文由哈喽比特于4年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/524RYPNXiTpclBatdIlGqw
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。