反应依赖注入或类似?

Blu*_*xir 27 dependency-injection angularjs reactjs

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

And*_*ahl 22

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

将依赖关系作为道具传递并不是React世界常见的.道具主要用于将数据传递给组件而不是服务/商店.但是没有什么可以阻止你将服务/商店甚至组件作为道具传递(当然也没有任何问题).

React具有a的概念,context它是整个组件树的共享对象.因此,顶级组件可以说其子树的上下文具有包含诸如UserStore,MessageStore等内容的对象.然后,组件层次结构中更下面的组件可以说它想要在其上下文中访问UserStore.通过这样说,UserStore可以被该组件访问,而不必明确地将其从顶层组件传递到底层,并且请求它的组件不知道它是如何创建/传递给它的.

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

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


Lar*_*röm 6

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

如果我们排除上下文,那么在React组件中注入内容的规范方法是使用props.运行时会注入道具React.createElement,即每个jsx标签.该React.createElement函数接受一个组件,一些道具和一些子项,并返回一个React元素.即(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
        );
    };
};
Run Code Online (Sandbox Code Playgroud)

返回的组件可以在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} />;
}
Run Code Online (Sandbox Code Playgroud)

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

关于这一点的好处是PropTypes仍然可以很好地工作,因此每个组件都可以清楚地声明它想要的属性类型.

此外,注入的接收端不需要依赖任何特殊的实现,只需要React的普通道具系统.因此,组件无需知道您正在使用依赖注入或如何使用依赖注入,他们只关心他们接收的道具.

  • @ crh225我现在更新了小提琴。 (2认同)

Rem*_*sen 6

反应模式

React 组件中的大多数依赖注入的解决方案都是基于 context 的。我认为了解幕后发生的事情很好。在撰写本文时,构建 React 应用程序的最流行方法之一涉及 Redux。著名的 connect 函数和那里的 Provider 使用上下文。

从反应文档

上下文是一项高级和实验性的功能。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>
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

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

您可以在此处了解更多信息。