使用带有自定义挂钩的 useContext 与 useContext + useReducer
using useContext with custom hooks vs useContext + useReducer
最近进入一个项目,在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(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 个遵循相同的模式,该项目有 4 个嵌套 providers/contexts.
我最初的想法是,它正在匿名改变状态,因为它没有全局定义的状态,也没有捕捉动作以更新全局状态的减速器。
我说得对吗?这是不那么推荐的处理状态的方法吗?如果我看到了这个模式,如果它有名字的话,它叫什么?
我正要建议更改为使用 context + useReducer 和 action 和 dispatch,但我需要更好地理解上述内容。
编辑:
为清楚起见:provders 嵌套如下:
const StoreProvider = ({ children }) => (
<CurrencyProvider>
<UserStoreProvider>
<CartStoreProvider>
<NotificationsStoreProvider>
{children}
</NotificationsStoreProvider>
</CartStoreProvider>
</UserStoreProvider>
</CurrencyProvider>
);
我对这种方法持怀疑态度,拥有一个上下文并让 useReducer/Redux 管理状态更新会更有效吗?
我想上面的例子(编辑部分)是为了防止在状态更新时重新渲染,如果你不使用减速器,这可能是有意义的。
上面提供的代码示例有两部分。一是状态管理(用useState
完成,二是状态提供者(用上下文完成)。让我们分开讨论它们。
一般来说,useState
、useReducer
和Redux reducer都是一样的。它们都允许拥有一些状态并基于它渲染组件。它们在允许操作状态的方式上有所不同,尤其是在复杂的情况下。
useState
是最简单的方法。你所能做的就是
const [state, setState] = useState()
setState(/* some new state */)
// or
setState(prevState => ({ ...prevState, /* some new state */ }))
操作状态时很难添加逻辑。 IE。如果你想在调用 setCurrency
之前进行货币转换,你应该在某个地方进行,或者编写自定义挂钩。而这个自定义钩子将是您对 Redux 操作的实现。
执行异步代码(获取货币汇率)会更加困难。不要忘记在 useEffect
中获取速率是不够的,因为您必须处理服务器错误(5xx 或 4xx)并向用户显示适当的消息。要存储错误,您可能需要额外的状态,或将其放入货币状态。
按照这种处理复杂状态的方法将引导您自己编写 Redux。
useReducer
(这是 React reducer,不是 Redux)允许通过操作来操作复杂的状态。 IE。您将能够分别发送 SET_CURRENCY
操作和 SET_RATES
操作,并且 useReducer
将相应地更新状态。但它没有任何异步代码逻辑(即从服务器获取速率)。你应该用自定义钩子自己写。
Redux 是处理状态的最复杂的方法。它允许使用操作更新部分状态并处理异步操作。如果您考虑 Redux Toolkit 这样的库,您将能够从项目中删除大量样板代码并使用复杂的状态更新逻辑。
根据我的经验,useState
用于简单状态,例如打开对话框。所有其他状态都转到 Redux。
另外,我可以提到表单的状态,它可以用 Reach Hook Forms 这样的库来操作。 React hook 表单将在内部保存表单特定状态并为您提供表单特定状态,如错误、触摸、提交计数等。
所提供示例中的第二部分是状态提供程序部分。它是根据上下文完成的。这是预料之中的,因为 useState
没有建议将状态传递给组件。 Redux 也使用上下文,但它是由 React-Redux 库为您创建的。此外,React-Redux 将为您提供有用的工具,例如 useSelector
到 select 仅部分状态。 React 上下文没有任何 select 或。它会给你完整的状态,你必须使用 useMemo
来获取部分状态并将其传递给较低级别的组件。同样,这类似于自己编写 React-Redux 库。
最后一个问题。提供的代码中没有使用方法的名称或模式。一些开发人员只是为一个项目发明了它。从我的角度来看,这种方法没有什么有趣的。
最近进入一个项目,在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(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 个遵循相同的模式,该项目有 4 个嵌套 providers/contexts.
我最初的想法是,它正在匿名改变状态,因为它没有全局定义的状态,也没有捕捉动作以更新全局状态的减速器。
我说得对吗?这是不那么推荐的处理状态的方法吗?如果我看到了这个模式,如果它有名字的话,它叫什么?
我正要建议更改为使用 context + useReducer 和 action 和 dispatch,但我需要更好地理解上述内容。
编辑:
为清楚起见:provders 嵌套如下:
const StoreProvider = ({ children }) => (
<CurrencyProvider>
<UserStoreProvider>
<CartStoreProvider>
<NotificationsStoreProvider>
{children}
</NotificationsStoreProvider>
</CartStoreProvider>
</UserStoreProvider>
</CurrencyProvider>
);
我对这种方法持怀疑态度,拥有一个上下文并让 useReducer/Redux 管理状态更新会更有效吗?
我想上面的例子(编辑部分)是为了防止在状态更新时重新渲染,如果你不使用减速器,这可能是有意义的。
上面提供的代码示例有两部分。一是状态管理(用useState
完成,二是状态提供者(用上下文完成)。让我们分开讨论它们。
一般来说,useState
、useReducer
和Redux reducer都是一样的。它们都允许拥有一些状态并基于它渲染组件。它们在允许操作状态的方式上有所不同,尤其是在复杂的情况下。
useState
是最简单的方法。你所能做的就是
const [state, setState] = useState()
setState(/* some new state */)
// or
setState(prevState => ({ ...prevState, /* some new state */ }))
操作状态时很难添加逻辑。 IE。如果你想在调用 setCurrency
之前进行货币转换,你应该在某个地方进行,或者编写自定义挂钩。而这个自定义钩子将是您对 Redux 操作的实现。
执行异步代码(获取货币汇率)会更加困难。不要忘记在 useEffect
中获取速率是不够的,因为您必须处理服务器错误(5xx 或 4xx)并向用户显示适当的消息。要存储错误,您可能需要额外的状态,或将其放入货币状态。
按照这种处理复杂状态的方法将引导您自己编写 Redux。
useReducer
(这是 React reducer,不是 Redux)允许通过操作来操作复杂的状态。 IE。您将能够分别发送SET_CURRENCY
操作和SET_RATES
操作,并且useReducer
将相应地更新状态。但它没有任何异步代码逻辑(即从服务器获取速率)。你应该用自定义钩子自己写。Redux 是处理状态的最复杂的方法。它允许使用操作更新部分状态并处理异步操作。如果您考虑 Redux Toolkit 这样的库,您将能够从项目中删除大量样板代码并使用复杂的状态更新逻辑。
根据我的经验,useState
用于简单状态,例如打开对话框。所有其他状态都转到 Redux。
另外,我可以提到表单的状态,它可以用 Reach Hook Forms 这样的库来操作。 React hook 表单将在内部保存表单特定状态并为您提供表单特定状态,如错误、触摸、提交计数等。
所提供示例中的第二部分是状态提供程序部分。它是根据上下文完成的。这是预料之中的,因为 useState
没有建议将状态传递给组件。 Redux 也使用上下文,但它是由 React-Redux 库为您创建的。此外,React-Redux 将为您提供有用的工具,例如 useSelector
到 select 仅部分状态。 React 上下文没有任何 select 或。它会给你完整的状态,你必须使用 useMemo
来获取部分状态并将其传递给较低级别的组件。同样,这类似于自己编写 React-Redux 库。
最后一个问题。提供的代码中没有使用方法的名称或模式。一些开发人员只是为一个项目发明了它。从我的角度来看,这种方法没有什么有趣的。