Recoil 会成为 React 中的新 Redux 吗?

Recoil 是一个新的 React 状态管理库,可让我们以 Reactish 的方式管理全局/可共享状态。 很棒的是,Recoil 是由 Facebook 团队开发的。 在这篇文章中,我们将看看 useRecoilState 钩子,以及他们是如何让它变得如此“React”的?

让我们来看一个非常简单的问题陈述。

我们希望在两个兄弟/并行子组件中共享计数状态变量。

 

Recoil 会成为 React 中的新 Redux 吗?
Recoil 共享计数状态

 

const C1Component = () => {
    const [count, setCount] = useState(10)
}

const C2Component = () => {
    const [count, setCount] = useState(10)
}

第一个解决方案:Prop-Drilling

最简单的可能解决方案是将计数移动到一个共同的父级并通过属性传递它。

 

Recoil 会成为 React 中的新 Redux 吗?
Recoil prop drillin

 

const PComponent = () => {
    const [count, setCount] = useState(10);
    <P1Component count={count}>
    <P2Component count={count}>
}

const P1Component = () => {
    const {count} = props;
    <C1Component count={count}>
}

const P2Component = () => {
    const {count} = props;
    <C2Component count={count}>
}

这解决了我们的问题,但会导致以下问题

  • 这里我们有一个简单的关卡树,但如果我们有更多,比如 4 或 5 个关卡怎么办? 通过这么多级别的属性提取将使代码难以阅读
  • 整个组件树将重新渲染——而不仅仅是 2 个叶子组件。
  • 父组件将过载状态并可能导致不必要的重新渲染。

第二种解决方案:Context API

我们可以使用 React 的上下文 API。 上下文提供了一种通过组件树传递数据的方法,而无需在每个级别手动传递。

 

Recoil 会成为 React 中的新 Redux 吗?
Recoil 上下文API

 

const CountContext = React.createContext();

<CountContext.Provider value={42}>
    <PComponent />
</CountContext>


const C1Component = () => {
    const value = Readct.useContext(CountContext)
}

const C2Component = () => {
    const value = Readct.useContext(CountContext)
}

我们需要将父组件包装在 Context.Provider 中,子组件(C1&C2)可以使用 useContext 钩子订阅它。 这有助于我们避免螺旋提取。 但是,使用这种方法有一些限制:

  • 需要多个上下文提供者——一个 Context.Provider 只能共享一个值,而不是一组不确定的值——每个都有自己的消费者。
  • 复杂的单元测试用例——需要创建一个模拟提供者来编写单元测试用例。
  • 当上下文发生变化时,我们仍将重新渲染树中的每个组件。 (这就是为什么需要 redux 的原因,即使上下文可以在没有属性螺旋提取的情况下管理全局状态)

第三种解决方案:useRecoilState

最后我将介绍 useRecoilState,我们可以通过使用原子创建一个可共享的状态订阅单元轻松实现这一点。 为了利用 Recoil API,我们需要将父组件包装在 RecoilRoot 中。

 

Recoil 会成为 React 中的新 Redux 吗?
Recoil useRecoilState

 

const countAtom = atom({
    key: 'count', // unique ID
    default: 10        // 默认值(初始值)
})

const CountContext = React.createContext();

<CountContext.Provider value={42}>
    <PComponent />
</CountContext>


const C1Component = () => {
    const [count, setCount] = useRecoilState(countAtom)
}

const C2Component = () => {
    const [count, setCount] = useRecoilState(countAtom)
}

让我们看看为什么 Recoil 被称为“Reactish”和“Minimal”。

import {atom, useRecoilState} from 'recoil';

<RecoilRoot>
    <PComponent />
</RecoilRoot>

const countAtom = atom({
    key: 'count', // unique ID
    default: 10        // 默认值(初始值)
})

const CountContext = React.createContext();

<CountContext.Provider value={42}>
    <PComponent />
</CountContext>


const C1Component = () => {
    const [count, setCount] = useState(10);
    const [count, setCount] = useRecoilState(countAtom)
}

const C2Component = () => {
    const [count, setCount] = useState(10);
    const [count, setCount] = useRecoilState(countAtom)
}

我比较 useState 和 useRecoilState 只是为了说明语法有多相似。 但是,Recoil 的功能可以与 Redux、MobX、Apollo GraphQL 等其他全局状态管理库进行比较。

结论:Recoil 仍处于实验阶段,但进展很快。

总结

在本文中,我们尝试向大家介绍 Recoil,这是 Meta 的 React 新状态管理库。 仍然处于实验阶段的 Recoil 是否会取代 Redux 尚无定论。 但它似乎确实具有潜力。