在 React Europe 2020 Conference
上,Facebook
软件工程师 Dave McCabe
介绍了一个新的状态治理库 Recoil
。
Recoil
当初还处于试验阶段,当初曾经在 Facebook
一些外部产品中用于生产环境。毕竟是官网推出的状态治理框架,之前没工夫认真钻研,借着国庆期间看了看,给大家分享一下。
State 和 Context 的问题
假如咱们有上面一个场景:有 List
和 Canvas
两个组件,List 中一个节点更新后,Canvas 中的节点也对应更新。
最常规定做法是将一个 state
通过父组件分发给 List
和 Canvas
两个组件,显然这样的话每次 state
扭转后 所有节点都会全量更新。
当然,咱们还能够应用 Context API
,咱们将节点的状态存在一个 Context
内,只有 Provider
中的 props
产生扭转,Provider
的所有后辈使用者都会从新渲染。
为了防止全量渲染的问题,咱们能够把每个子节点存储在独自的 Context
中,这样每多一个节点就要减少一层 Provider
。
然而,如果子节点是动静减少的呢?咱们还须要去动静减少 Provider
,这会让整个树再次从新渲染,显然也是不合乎预期的。
引入 Recoil
Recoil
自身就是为了解决 React
全局数据流治理的问题,采纳扩散治理原子状态的设计模式。
Recoil
提出了一个新的状态治理单位 Atom
,它是可更新和可订阅的,当一个 Atom
被更新时,每个被订阅的组件都会用新的值来从新渲染。如果从多个组件中应用同一个 Atom
,所有这些组件都会共享它们的状态。
你能够把 Atom
设想为为一组 state
的汇合,扭转一个 Atom
只会渲染特定的子组件,并不会让整个父组件从新渲染。
用 Redux 或 Mobx 不能够吗?
因为 React
自身提供的 state
状态在跨组件状态共享上十分苦难,所以咱们在开发时个别借助一些其余的库如 Redux、Mobx
来帮忙咱们治理状态。这些库目前正被宽泛应用,咱们也并没有遇到什么大问题,那么 Facebook
为什么还要推出一款新的状态治理框架呢?
应用 Redux、Mobx
当然能够,并没有什么问题,次要起因是它们自身并不是 React
库,咱们是借助这些库的能力来实现状态治理。像 Redux
它自身尽管提供了弱小的状态治理能力,然而应用的老本十分高,你还须要编写大量简短的代码,另外像异步解决或缓存计算也不是这些库自身的能力,甚至须要借助其余的内部库。
并且,它们并不能拜访 React
外部的调度程序,而 Recoil
在后盾应用 React
自身的状态,在将来还能提供并发模式这样的能力。
根底应用
初始化
应用 recoil
状态的组件须要应用 RecoilRoot
包裹起来:
import React from 'react';
import {
RecoilRoot,
atom,
selector,
useRecoilState,
useRecoilValue,
useSetRecoilState
} from 'recoil';
function App() {
return (
<RecoilRoot>
<CharacterCounter />
</RecoilRoot>
);
}
定义状态
下面咱们曾经提到了 Atom
的概念,Atom
是一种新的状态,然而和传统的 state
不同,它能够被任何组件订阅,当一个 Atom
被更新时,每个被订阅的组件都会用新的值来从新渲染。
首先咱们来定义一个 Atom
:
export const nameState = atom({
key: 'nameState',
default: 'ConardLi'
});
这种形式意味着你不须要像 Redux
那样集中定义状态,能够像 Mobx
一样将数据扩散定义在任何中央。
要创立一个 Atom
,必须要提供一个 key
,其必须在 RecoilRoot
作用域中是惟一的,并且要提供一个默认值,默认值能够是一个动态值、函数甚至能够是一个异步函数。
订阅和更新状态
Recoil
采纳 Hooks
形式订阅和更新状态,罕用的是上面三个 API:
useRecoilState
:相似 useState 的一个Hook
,能够取到atom
的值以及setter
函useSetRecoilState
:只获取setter
函数,如果只应用了这个函数,状态变动不会导致组件从新渲染useRecoilValue
:只获取状态
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>;
}
派生状态
selector
示意一段派生状态,它使咱们可能建设依赖于其余 atom
的状态。它有一个强制性的 get
函数,其作用与 redux
的 reselect
或 MobX
的 @computed
相似。
const lengthState = selector({
key: 'lengthState',
get: ({get}) => {const text = get(nameState);
return text.length;
},
});
function NameLength() {const length = useRecoilValue(charLengthState);
return <>Name Length: {length}</>;
}
selector 是一个纯函数:对于给定的一组输出,它们应始终产生雷同的后果(至多在应用程序的生命周期内)。这一点很重要,因为选择器可能会执行一次或屡次,可能会重新启动并可能会被缓存。
异步状态
Recoil
提供了通过数据流图将状态和派生状态映射到 React
组件的办法。真正弱小的性能是图中的函数也能够是异步的。这使得咱们能够在异步 React
组件渲染函数中轻松应用异步函数。应用 Recoil
,你能够在选择器的数据流图中无缝地混合同步和异步性能。只需从选择器 get
回调中返回 Promise
,而不是返回值自身。
例如上面的例子,如果用户名存储在咱们须要查问的某个数据库中,那么咱们要做的就是返回一个 Promise
或应用一个 async
函数。如果 userID
产生更改,就会主动从新执行新查问。后果会被缓存,所以查问将仅对每个惟一输出执行一次(所以肯定要保障 selector 纯函数的个性,否则缓存的后果将会和最新的值不统一)。
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>;
}
Recoil
举荐应用 Suspense
,Suspense
将会捕捉所有异步状态,另外配合 ErrorBoundary
来进行谬误捕捉:
function MyApp() {
return (
<RecoilRoot>
<ErrorBoundary>
<React.Suspense fallback={<div>Loading...</div>}>
<CurrentUserInfo />
</React.Suspense>
</ErrorBoundary>
</RecoilRoot>
);
}
总结
Recoil
推崇的是分散式的状态治理,这个模式很相似于 Mobx
,应用起来也感觉有点像 observable + computed
的模式,然而其 API 以及核心思想设计的又没有 Mobx
一样简洁易懂,反而有点简单,对于新手上手起来会有肯定老本。
在应用形式上齐全拥抱了函数式的 Hooks
应用形式,并没有提供 Componnent
的应用形式,目前应用原生的 Hooks API
咱们也能实现状态治理,咱们也能够应用 useMemo
发明出派生状态,Recoil
的 useRecoilState
以及 selector
也比拟像是对 useContext、useMemo
的封装。
然而毕竟是 Facebook
官网推出的状态治理框架,其主打的是高性能以及能够利用 React
外部的调度机制,包含其承诺行将会反对的并发模式,这一点还是十分值得期待的。
另外,其自身的扩散治理原子状态的模式、读写拆散、按需渲染、派生缓存等思维还是十分值得一学的。
最初
文章中如有谬误,欢送在评论区斧正;如果文章对你有帮忙,欢送点赞、评论、分享、心愿能帮到更多人。
本文首发于公众号《code 机密花园》欢送大家关注,原文:Facebook 新一代 React 状态治理库 Recoil