与useContext+useReducer相比,使用带有自定义挂钩的useContext



我最近进入了一个项目,在react中使用上下文时看到了一些我以前从未见过的东西。

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

代码:

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

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

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

供应商:

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个遵循相同模式的提供者/上下文,并且该项目有四个嵌套提供者/上下文。

我最初的想法是,它正在匿名地改变状态,因为它没有全局定义的状态,也没有为了更新全局状态而捕捉动作的减少器。

我说得对吗?这是不是不推荐的处理状态的方法?如果我担心,如果这个模式有名字,它叫什么?

我本来打算建议改为使用context+useReducer和action和dispatch,但我需要更好地理解上面的内容。

编辑:

为了清楚起见:证明者是这样嵌套的:

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

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

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

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

一般情况下,useStateuseReducer和Redux减速器都是相同的。它们都允许有一些状态并基于它呈现组件。它们在允许操作状态的方式上有所不同,尤其是在复杂的情况下。

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

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

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

在复杂状态下遵循这种方法将引导您自己编写Redux。

  1. useReducer(这是React reducer,而不是Redux(允许通过操作操作复杂状态。也就是说,您将能够分别调度SET_CURRENCY动作和SET_RATES动作,并且useReducer将一致地更新状态。但它并没有任何异步代码的逻辑(即从服务器获取速率(。你应该用自定义钩子自己写。

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

根据我的经验,useState是用于简单状态的,就像打开对话框一样。所有其他州都归Redux所有。

此外,我还可以提到表单的状态,它可以使用ReachHookForms这样的库进行操作。React hook表单将在内部保存表单特定状态,并为您提供表单特定的状态,如错误、触摸、提交计数等。

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

还有最后一个问题。提供的代码中使用的方法没有名称或模式。一些开发人员刚刚为一个项目发明了它。从我的角度来看,这种做法没有什么意思。

最新更新