桥接模式容器模式主机模式_容器模式,以更好地进行状态管理

桥接模式容器模式主机模式

介绍(Introduction)

The container pattern is a concept introduced in the Unstated-Next library. This pattern thinks about states as varieties of Containers that hold a modular slice of the global application state. To provide this state you create a Context across your application, then access it through hooks.

容器模式是Unstated-Next库中引入的概念。 这种模式将状态视为Containers变体,这些Containers全局应用程序状态的模块化切片。 为了提供这种状态,您可以在整个应用程序中创建一个Context,然后通过钩子对其进行访问。

Compared to something like Redux, this Container pattern offers a Hook-centric way to manage state. It’s easier to learn, scales with your application well , and provides an intuitive way to think about global state. Here’s how it works.

与Redux之类的东西相比,这种Container模式提供了一种以Hook为中心的方式来管理状态。 它易于学习,可以很好地随应用程序扩展,并提供了一种思考全局状态的直观方法。 运作方式如下。

什么是容器模式? (What’s the Container Pattern?)

The container pattern is a methodology in which instead of having all your global state in one external library or global store, such as Redux, you divide that state into multiple chunks called containers. These chunks are responsible for managing their own state and can be pulled into any functional component in the app, using something similar to the following syntax:

容器模式是一种方法,您无需将所有全局状态都存储在一个外部库或全局存储(例如Redux)中,而是将该状态分为多个称为容器的块。 这些块负责管理它们自己的状态,并且可以使用类似于以下语法的方式放入应用程序的任何功能组件中:

const {user} = Auth.useContainer();

This pattern works really well because it divides state into self-managing chunks rather than having everything intertwined. Each component can simple pull in the chunk of state that it wants to use and is only dependent on a part of your applications state.

这种模式非常有效,因为它将状态划分为自我管理的块,而不是将所有事物交织在一起。 每个组件都可以简单地提取其要使用的状态块,并且仅取决于应用程序状态的一部分。

Each chunk of state is easy to reason about. They’re simply a custom hooks wired up to context providers — that’s it. The term “Container” really just means “a React Custom Hook and a Context Provider.” So when someone is recommending state management with Hooks and useContext, they’re technically recommending this container pattern.

每个状态块都很容易推断。 它们只是连接到上下文提供者的自定义钩子,仅此而已。 术语“容器”实际上仅表示“ React自定义挂钩和上下文提供者”。 因此,当有人建议使用Hooks和useContext进行状态管理时,他们在技术上建议使用此容器模式。

To use containers you just have to import the Context and use the hook. You don’t technically need any external libraries, however I use a library called Unstated-Next because it gives me some benefits that make this pattern even easier.

要使用容器,只需导入上下文并使用挂钩。 从技术上来说,您不需要任何外部库,但是我使用了一个称为Unstated-Next的库,因为它给了我一些好处,使该模式更加容易。

什么是未声明的下一个? (What is Unstated-Next?)

Unstated-Next is a tiny library that helps us reason about these global containers a little bit easier. This library is tiny (like 200 bytes tiny) — for good reason, it basically doesn’t do anything that React’s Context API doesn’t already do.

Unstated-Next是一个微型库,可以帮助我们更轻松地推断这些全局容器。 这个库很小(例如200字节很小)—出于充分的理由,它基本上不执行React的Context API尚未执行的任何操作。

This library is 100% optional for this design pattern. It just provides some small API improvements that make Context easier to work with. Some of the main benefits include:

对于该设计模式,该库是100%可选的。 它只是提供了一些小的API改进,使Context更易于使用。 一些主要好处包括:

  • Type-Checking: This gives you typescript support out of the box. This was one of my gripes with using the React Context API, so it’s nice to see that unstated-next solves the issue.

    类型检查:开箱即用为您提供打字稿支持。 这是我使用React Context API的烦恼之一,因此很高兴看到unstated-next解决了这个问题。

  • Error Handling: If you try to access a container that doesn’t have a Context provider above it in the React DOM tree, it will throw an error. This is a life-saver for debugging.

    错误处理:如果您尝试访问一个在React DOM树中上方没有Context提供程序的容器,它将抛出错误。 这是调试的救命稻草。

  • Easier to Think About: Thinking about contexts can seem abstract at times, but using this library with the mental concept of “containers” is a lot easier.

    易于思考:有时对上下文的思考似乎很抽象,但是将这个库与“容器”的心理概念结合使用会容易得多。

这种模式是什么样的? (What Does This Pattern Look Like?)

Image for post

档案结构 (File structure)

When I use this pattern, I put all my containers in a “container” folder at the root of the src directory. I suffix each container with the word “Container” and have all the relevant code in one file.

使用这种模式时,我将所有容器放在src目录根目录下的“容器”文件夹中。 我在每个容器后缀“ Container”,并将所有相关代码放在一个文件中。

This already has benefits over something like Redux, where a single responsibility might be divided over three or four files for the actions, reducer, store, selectors etc.

与Redux之类的东西相比,这已经具有了好处,在Redux中,一个动作可以分为三个或四个文件,分别用于操作,reduce,存储,选择器等。

Image for post

容器文件 (The container file)

The container is where your slice of state will live. This file contains everything necessary for reading and writing to this part of state. Here’s what a container file may look like for an AuthContainer:

容器是您的状态片所在的位置。 该文件包含读取和写入此状态部分所需的所有内容。 这是AuthContainer的容器文件的外观:

// The reducer. This would be very similar to your reducer in Redux.
// This is optional, you can just use useState instead, but this is
// here to show that if you want to use a reducer and do more
// complicated state transitions you can.
function authReducer(state: AuthState, action: Action) {
...
}// Custom Hook
function useAuth(initialState: AuthState) {
const [state, dispatch] = useReducer(authReducer, initialState);const loginWithGoogle = () => {
dispatch(loggingIn());
doGoogleLogin()
.then(user => dispatch(success(user)))
.catch(err => dispatch(error(err.message)));
}const loginWithEmailPassword = (email, password) => {
dispatch(loggingIn());
doEmailPasswordLogin(email, password)
.then(user => dispatch(success(user)))
.catch(err => dispatch(error(err.message)));
}const logout = () => dispatch(logout());return {
user: state.data,
isAuthenticating: state.loading,
error: state.error,
loginWithGoogle,
loginWithEmailPassword,
logout
};
}// Create the Container (this can be a Context too)
// You just pass in the custom hook that you want to build the
// container for.
export const Auth = createContainer(useAuth);

This is really clean — it’s basically just a custom hook and then that one little line at the bottom to make it a container. When you add that container code at the bottom, it makes this custom hook have the same state, even if used in multiple different components. This is because the Unstated-Next containers just use the Context API under the hood.

这真的很干净-它基本上只是一个自定义钩子,然后在底部留一行以使其成为容器。 当您在底部添加该容器代码时,即使在多个不同的组件中使用,它也使此自定义挂钩具有相同的状态。 这是因为Unstated-Next容器仅在Unstated-Next使用Context API。

To make that work you first need to add a Store to your application which will store all the containers. This might look something like this:

为了使这项工作,首先需要一个添加Store到你的应用程序将保存所有的容器。 可能看起来像这样:

Image for post

Note: I think there could be a better way to manage a Store like this. If we could dynamically create this structure based on an array of containers, or something like that, I think that would be a lot cleaner.

注意:我认为可能会有更好的方法来管理这样的Store 如果我们可以基于一组容器或类似的容器动态创建此结构,那我认为这样会更清洁。

Also, if there was a way to make all these load at the same level of the DOM so any container could access any other container, that would be amazing too. Sadly I think that’s a limitation of React.

另外,如果有一种方法可以将所有这些负载都放在DOM的同一级别上,以便任何容器都可以访问任何其他容器,那也将是惊人的。 可悲的是,我认为这是React的局限性。

Put this in the root component, so your root component looks something like this:

将其放在根组件中,因此您的根组件看起来像这样:

const App: React.FC = () => {
return (
<Store>
<ReactRouter>
<AppRoutes>
</ReactRouter>
</Store>
);
}

And voila! If you did this correctly, you should now be able to go into any of your React components and use this hook like this:

! 如果您正确地做到了这一点,那么您现在应该可以进入任何React组件并像下面这样使用该钩子:

const LoginPage: React.FC = () => {   ...   const {
formLogin,
googleLogin,
isAuthenticating,
user
} = Auth.useContainer(); useEffect(() => {
if (user) {
history.push('/home');
}
}, [user]); ... return (
<div>
<button onClick={() => googleLogin()}>
Login with Google
</button> ... </div>
);
}

If you did everything right, following this pattern should work! If you did something wrong Unstated-Next might throw an error that says that the container’s provider hasn’t been created. But that’s good because it’s an explicit error message for a bug that would be really difficult to track down if you were using the basic React Context!

如果您做对了所有事情,遵循此模式应该可以工作! 如果您做错了什么, Unstated-Next可能会抛出一个错误,提示尚未创建容器的提供程序。 但这很好,因为这是一条明确的错误消息,如果您使用的是基本的React Context,将很难真正找到该错误!

为什么不使用Redux? (Why Not Use Redux?)

Redux is great for state management at a large scale. It’s the tried-and-tested way to manage state for large applications. However, for the vast majority of applications out there, Redux is the wrong place to start. It’s very boilerplate heavy and probabbly won’t give you many benefits unless you already know you need it.

Redux非常适合大规模的状态管理。 这是管理大型应用程序状态的久经考验的方式。 但是,对于绝大多数应用程序来说,Redux是错误的起点。 它非常笨拙,除非您已经知道需要,否则不会给您带来很多好处。

So I’m offering this pattern as an alternative.

因此,我提供了这种模式作为替代。

The main benefit you get from this pattern is that it makes more sense from a developer’s perspective. Redux takes your state and pulls it away from the view layer. I’d argue that a better way to manage state would be to colocate it with the view layer that uses it.

从这种模式中获得的主要好处是,从开发人员的角度来看,它更有意义。 Redux获取您的状态并将其从视图层拉开。 我认为更好的管理状态的方法是将其与使用状态的视图层并置。

This is why React Hooks exist.

这就是存在React Hooks的原因。

You can already see things moving towards this methodology with the movement of other pieces of state out of things like Redux and into hooks:

您已经看到其他状态从Redux之类进入钩子的过程正在朝着这种方法发展:

So, it makes sense that the global state also be built to fit well into a hook ecosystem.

因此,有意义的是,还应将全球状态构建为非常适合钩子生态系统。

The majority of my state management is done by various hook libraries, so it makes sense that my global state management also be hook-centric.

我的大多数状态管理都是由各种挂钩库完成的,因此,我的全局状态管理也应以挂钩为中心。

The container pattern implements this idea. It offers the majority of the functionality as Redux at a fraction of the time-cost and is designed with hook-centric development in mind.

容器模式实现了这个想法。 它以Redux的形式提供了大多数功能,而时间成本却很少,并且在设计时考虑了以钩子为中心的开发。

For any small-medium sized-project, this pattern is a no-brainer for me. For a larger project, it depends on the use-case.

对于任何中小型项目而言,这种模式对我来说都不是难事。 对于较大的项目,这取决于用例。

Here are some comparisons between the container pattern and Redux:

以下是容器模式和Redux之间的一些比较:

容器模式具有以下优点: (The Container pattern has the following benefits:)

  • Less boilerplate than something like Redux.

    比Redux少样板。
  • Uses the native Context API under the hood.

    在后台使用本机Context API。
  • You can learn the API in 10 minutes if you know useState, useContext and Custom Hooks.

    如果您知道useStateuseContext和Custom Hooks,则可以在10分钟内学习API。

  • Only uses one tiny library, and even that dependency is optional.

    仅使用一个很小的库,即使依赖关系也是可选的。

它还具有以下缺点: (It also has the following cons:)

  • No support for middlewares.

    不支持中间件。
  • No tool akin to the Redux chrome debugger.

    没有类似于Redux Chrome调试器的工具。
  • Containers must be provided in a certain order if they have dependencies on each other.

    如果容器相互依赖,则必须按一定顺序提供容器。

With this in mind, hopefully, you now have a better idea of what alternatives there are if your use-case doesn’t need something as bulky as Redux.

考虑到这一点,希望您现在对如果用例不需要像Redux那样庞大的东西有了更好的选择。

If you want to employ this pattern but can’t quite leave Redux, another alternative would be a using Redux Toolkit and a Redux Ducks Pattern.

如果您想采用此模式但又不能完全离开Redux,则另一种选择是使用Redux工具包和一个Redux鸭子图案

Image for post
Redux Ducks
Redux鸭

This Redux Ducks approach works well if you’re building a large application because it uses a container-focused methodology, but still keeps you in the ecosystem of Redux.

如果您正在构建大型应用程序,则此Redux Ducks方法会很好用,因为它使用了以容器为中心的方法,但仍使您处于Redux生态系统中。

结论 (Conclusion)

That’s the Container pattern. If you’re looking at using Redux in an app, I would take a serious look at the cost of doing so to determine if your application actually requires it. I think this pattern is a good place to start regardless, and because it’s so small and modular you can easily migrate it into Redux in the future.

那就是Container模式。 如果您要在应用程序中使用Redux,我会认真考虑这样做的成本,以确定您的应用程序是否真正需要它。 我认为无论如何,这种模式都是一个很好的起点,并且由于它很小且模块化,您将来可以轻松地将其迁移到Redux。

Overall, this pattern has helped me clean up my codebase a lot. It’s also helped me remove state management from my list of pain-points when developing applications.

总的来说,这种模式帮助我清理了很多代码库。 在开发应用程序时,它还帮助我从痛点列表中删除了状态管理。

Let me know what you think — hopefully it will work well in your projects. Enjoy!

让我知道您的想法-希望它可以在您的项目中很好地工作。 请享用!

翻译自: https://medium.com/better-programming/the-container-pattern-for-better-state-management-in-react-9351fe4381d1

桥接模式容器模式主机模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值