反应依赖注入或类似?

时间:2015-05-18 19:09:51

标签: angularjs dependency-injection reactjs

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

3 个答案:

答案 0 :(得分:23)

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

将依赖项作为道具传递并不是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版本中更改,因此您可能希望在它被记录之前稀疏地使用它。

答案 1 :(得分:6)

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

如果我们排除上下文,那么在React组件中注入内容的规范方法是使用props。运行React.createElement时会注入道具,即每个jsx标签。 React.createElement函数接受一个组件,一些道具和一些子项,并返回React element。即(component, props, children) -> element

我创建了createComponent函数,其签名与React.createElement几乎相同,但它返回了一个组件,即(component, props, children) -> 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的普通道具系统。因此,组件不需要知道您使用依赖注入或如何使用依赖注入,他们只关心他们接收的道具。

答案 2 :(得分:4)

来自react-in-patterns

  

React组件中依赖注入的大多数解决方案都基于上下文。我认为了解引擎盖下发生的事情会很好。在撰写本文时,构建React应用程序的最常用方法之一涉及Redux。着名的连接函数和提供者使用上下文。

来自反应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