【问题标题】:React dependency injection or similar?反应依赖注入或类似?
【发布时间】:2015-05-18 19:09:50
【问题描述】:

在 Angular.js 中可以使用依赖注入。我做了一些浏览,但找不到它的实现。 React 有类似的东西吗?

【问题讨论】:

    标签: angularjs dependency-injection reactjs


    【解决方案1】:

    React 有 IoC,但没有像 Angular 这样的 DI 容器的概念。也就是说,不是让容器知道如何创建对象并传递依赖项,而是在实例化组件时通过将 props 传递给组件来显式传递它们(如 <MyComponent items={this.state.items} />)。

    不过,将依赖项作为 props 传递在 React 世界中并不常见。道具主要用于将数据传递给组件而不是服务/商店。但是没有什么能阻止您将服务/商店甚至组件作为道具传递(当然也没有错)。

    React 有context 的概念,它是整个组件树的共享对象。所以顶级组件可以说它的子树的上下文有一个对象,其中包含类似 UserStore、MessageStore 等的东西。组件层次结构中更靠后的组件可以说它想要访问其上下文中的 UserStore。话虽如此,该组件可以访问 UserStore,而无需将其从顶部组件显式传递到底部,并且请求它的组件不知道它是如何创建/传递给它的。

    它具有 DI 容器的好处,您可以在其中有一个创建对象的中心位置,可以进一步向下传递。这是对上下文的一个很好的介绍:https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html

    上下文仍然是 React 的一个未记录的特性,这意味着它的 API 可以在任何即将到来的 React 版本中更改,因此您可能希望稀疏地使用它,直到它被记录。

    【讨论】:

      【解决方案2】:

      来自react-in-patterns

      React 组件中依赖注入的大部分解决方案都是基于上下文的。我认为很高兴知道引擎盖下发生了什么。在撰写本文时,最流行的构建 React 应用程序的方法之一就是 Redux。著名的连接函数和那里的 Provider 使用上下文。

      从反应docs:

      上下文是一项高级且实验性的功能。 API 可能会在未来的版本中发生变化。

      大多数应用程序永远不需要使用上下文。特别是如果你刚刚开始使用 React,你可能不想使用上下文。使用上下文会使您的代码更难理解,因为它会使数据流变得不那么清晰。它类似于使用全局变量通过您的应用程序传递状态。

      如果必须使用上下文,请谨慎使用。

      无论您是在构建应用程序还是库,请尽量将您对上下文的使用隔离到一个小区域,并尽可能避免直接使用上下文 API,以便在 API 更改时更容易升级。

      由于使用了 IoC 容器,我找到了一种无需使用上下文即可注入依赖项的方法。

      大多数容器支持两种注入:

      • 构造函数注入:为了使用“构造函数注入”,IoC 容器需要能够创建类的实例。在 React 中,组件有时只是函数(而不是类),我们不能将组件实例的创建委托给 IoC 容器。这意味着由 IoC 容器提供支持的构造函数注入不能很好地与 React 配合使用

      • 属性注入:如果我们想要将依赖项传递给组件而不是显式地通过每个组件传递,则与 React 配合得很好

      我使用 InversifyJS 作为 IoC 容器,它的属性注入支持将依赖项传递给组件,而无需通过每个组件显式传递它们,也无需使用上下文:

      import { pInject } from "./utils/di";
      import { UserStore } from "./store/user";
      
      class User extends React.Component<any, any> {
      
          @pInject(UserStore)
          private userStore: UserStore; // INJECTED!
      
          public render() {
              return (
                  <h1>{this.userStore.pageTitle}</h1>
              );
          }
      }
      

      使用像 InversifyJS 这样的 IoC 容器的主要优点是我们不使用上下文!

      您可以通过here了解更多信息。

      【讨论】:

        【解决方案3】:

        我不太喜欢使用 contexts,因为它仍然是 react 的一个实验性功能,而且有点笨重。我也看过像 react-di 这样的 DI 框架,但它要求每个组件都知道 DI 框架注入依赖项的方式(即知道依赖项在 this.props.di 对象中。)。

        如果我们排除上下文,将某些东西注入 React 组件的规范方法是通过使用 props。当你运行React.createElement 时,props 被注入,即对于每个 jsx 标签。 React.createElement 函数接受一个组件、一些道具和一些孩子,并返回一个React element。 IE。 (component, props, children) -&gt; element.

        我创建了一个createComponent 函数,其签名与React.createElement 几乎相同,但它返回一个组件,即(component, props, children) -&gt; component。这里是:

        const createComponent = (type, defaultProps = {}, defaultChildren = null) => {
            return ({ children, ...props }) => {
                return React.createElement(
                    type,
                    { ...defaultProps, ...props },
                    children || defaultChildren
                );
            };
        };
        

        返回的组件可以注入到一个 prop 中,如下例所示:

        const Banner = ({ children, TextComponent }) => {
            return <div className="banner">
                <TextComponent>{children}</TextComponent>
            </div>;
        }
        
        const SayHelloComponent = ({ ParagraphComponent }) => {
            return <ParagraphComponent>Hello world!</ParagraphComponent>;
        }
        
        const ParentComponent = () => {
            const inject = {
                ParagraphComponent: createComponent(Banner, {
                    TextComponent: createComponent('span', {
                        className: "my-pretty-class",
                    }),
                }),
            }
        
            return <SayHelloComponent {...inject} />;
        }
        

        小提琴:https://jsfiddle.net/8971g8s5/3/

        这样做的好处是PropTypes 仍然可以很好地工作,因此每个组件都可以清楚地声明它想要什么样的属性。

        另外,注入的接收端不需要依赖任何特殊的实现,只需要 React 的普通 props 系统。所以组件不需要知道你正在使用依赖注入或者你是怎么做的,他们只关心他们收到了什么道具。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-04-20
          • 2020-01-06
          • 1970-01-01
          • 2017-09-04
          • 1970-01-01
          • 1970-01-01
          • 2012-03-16
          相关资源
          最近更新 更多