【问题标题】:using useContext with custom hooks vs useContext + useReducer使用带有自定义钩子的 useContext 与 useContext + useReducer
【发布时间】:2022-01-24 01:40:27
【问题描述】:

我最近进入一个项目,在 react 中的 useContext 时看到了一些我以前没有见过的东西。

项目中的全局状态使用它发送到上下文的钩子,然后在稍后调用该钩子时全局状态是可访问的。我看到的问题是在一个地方没有定义全局状态,您可以创建一个带有状态和更新功能的钩子,将其发送给提供者并在项目中的任何地方访问它..

代码:

const initialState = {
  id: "MyId",
  currency: 'currency',
};


function useCurrencyState() {
  initialState.currency = 'newCurrency'
  const [currency, setCurrency] = React.useState(initialState);

  return {
    currency
  };
}


export const [useCurrency, CurrencyStoreProvider] = createStoreProvider(useUserState);

提供者:

export function createStoreProvider(useHook) {
  const [useContextConsumer, ContextProvider] = generateContext();

  const StoreProvider = ({ children }) => {
    const state = useHook();

    return <ContextProvider value={state}>{children}</ContextProvider>;
  };

  return [useContextConsumer, StoreProvider];
}

生成上下文函数:

export function generateContext() {
  const context = React.createContext(undefined);

  const useContextConsumer = () => {
    const c = React.useContext(context);
    if (!c) {
      throw new Error('Component must be wrapped with <Container.Provider>');
    }
    return c;
  };

  return [useContextConsumer, context.Provider];
}

商店:

const StoreProvider = ({ children }) => (
  <CurrencyStoreProvider>
      {children}
  </CurrencyStoreProvider>
);

export default StoreProvider;

当你想使用 useCurrency 时

import { useCurrency } from 'store/currency';

 const { currency} = useCurrency ();

上面的例子是针对一个钩子的。该项目有 4 个遵循相同的模式,并且该项目有 4 个嵌套的提供程序/上下文。

我最初的想法是它是匿名地改变状态,因为它没有全局定义的状态,也没有捕捉动作以更新全局状态的 reducer。

我说的对吗?这是处理状态的不那么推荐的方式吗?如果我穿了这个图案,如果它有名字,它叫什么?

我正要建议更改为使用 context + useReducer 与 action 和 dispatch 但我需要更好地理解上述内容。

编辑:

为了清楚起见:提供者嵌套如下:

const StoreProvider = ({ children }) => (
<CurrencyProvider>
  <UserStoreProvider>
    <CartStoreProvider>
      <NotificationsStoreProvider>
        {children}
      </NotificationsStoreProvider>
    </CartStoreProvider>
  </UserStoreProvider>
</CurrencyProvider>
);

我对这种方法持怀疑态度,拥有 ONE 上下文并使用 useReducer/Redux 来管理状态更新会更有效吗?

我猜上面的例子(编辑部分)是为了防止在状态更新时重新渲染,如果你不使用减速器,这可能是有意义的。

【问题讨论】:

  • 我没有看到setCurrency 的用法。所以提供的代码不会改变货币状态。所有其他代码只是使用上下文为较低级别的组件提供状态。通常,上下文可用于简单状态。对于复杂的状态更喜欢 Redux。否则,您将自己编写 redux 逻辑。
  • @Fyodor 这是一个基本示例。还有其他使用 setfunction 的钩子。这里的重点是了解这种架构,并询问这种方法是否有特定的名称,我可以阅读更多内容,以及在多语言站点中处理状态时这是否“正确”。就我个人而言,我更喜欢与减速器相关的全局状态,但我不想在完全理解这一点并权衡利弊之前提出建议

标签: javascript reactjs state provider use-context


【解决方案1】:

上面提供的代码示例有两个部分。一是状态管理(使用useState 完成,二是状态提供者(使用上下文完成)。让我们分别讨论。

一般情况下,useStateuseReducer 和 Redux reducer 都是一样的。它们都允许拥有一些状态并基于它渲染组件。它们在允许操纵状态的方式上有所不同,尤其是在复杂情况下。

  1. useState 是一种最简单的方法。你所能做的就是
  const [state, setState] = useState()
  setState(/* some new state */)
  // or
  setState(prevState => ({ ...prevState, /* some new state */ }))

在操作状态时很难添加逻辑。 IE。如果您想在调用setCurrency 之前进行货币转换,您应该在某处进行,或者编写自定义挂钩。这个自定义钩子将是您对 Redux 操作的实现。

执行异步代码(获取货币汇率)将更加困难。不要忘记在useEffect 中获取速率是不够的,因为您必须处理服务器错误(5xx 或 4xx)并向用户显示适当的消息。要存储错误,您可能需要额外的状态,或将其置于货币状态中。

遵循这种复杂状态的方法将导致您自己编写 Redux。

  1. useReducer(这是 React reducer,而不是 Redux)允许使用操作来操作复杂的状态。 IE。您将能够分别调度 SET_CURRENCY 动作和 SET_RATES 动作,useReducer 将相应地更新状态。但它没有任何异步代码逻辑(即从服务器获取速率)。您应该使用自定义挂钩自己编写。

  2. Redux 是处理状态的最复杂的方法。它允许使用操作更新部分状态并处理异步操作。如果您考虑使用 Redux Toolkit 这样的库,您将能够从项目中删除大量样板代码并使用复杂的状态更新逻辑。

根据我的经验,useState 用于简单状态,例如打开对话框。所有其他状态都转到 Redux。

另外,我可以提一下表单的状态,可以用Reach Hook Forms这样的库来操作。 React 钩子表单将在内部保存表单特定状态,并为您提供表单特定状态,如错误、触摸、提交计数等。

所提供示例中的第二部分是状态提供者部分。它是通过上下文完成的。这是意料之中的,因为useState 没有建议将状态传递给组件。 Redux 也使用上下文,但它是由 React-Redux 库为您创建的。此外,React-Redux 将为您提供有用的工具,例如 useSelector 以仅选择部分状态。 React 上下文没有任何选择器。它将为您提供完整状态,您必须使用useMemo 获取部分状态并将其传递给较低级别​​的组件。同样,它类似于自己编写 React-Redux 库。

最后一个问题。提供的代码中没有方法的名称或模式。一些开发人员刚刚为一个项目发明了它。在我看来,这种方法没有什么有趣的。

【讨论】:

  • 好的,感谢您的精彩回答。如果我可能只是要求您看一下问题的编辑部分。我将推动使用带有 ONE 上下文的 useReducer,但在编辑部分您将能够看到有多个。你会说什么是推动使用一个上下文而不是嵌套上下文的最佳论据,如编辑部分所示?
  • 正如您已经提到的,不同的上下文用于防止重新渲染。但是也可以使用useMemoReact.memo 来防止重新渲染。我不认为多个上下文本身会降低应用程序的性能或类似的东西。而且单一上下文通常更易于管理。还要考虑到,useReducer 和 Redux 是完全不同的东西。我个人没有找到useReducer 的任何用例,但经常使用 Redux。
猜你喜欢
  • 2019-12-09
  • 2020-01-23
  • 1970-01-01
  • 2021-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多