在 Angular.js 中可以使用依赖注入。我做了一些浏览,但无法找到它的实现。React 有类似的东西吗?
react依赖注入或类似的?
React 有 IoC,但没有像 Angular 这样的 DI 容器的任何概念。也就是说,不是让容器知道如何创建对象和传递依赖项,而是通过在实例化组件时将 props 传递给组件来显式传递它们(如<MyComponent items={this.state.items} />)。
不过,将依赖项作为 props 传递在 React 世界中并不常见。props主要用于将数据传递给组件而不是服务/商店。但是没有什么可以阻止您将服务/商店甚至组件作为props传递(当然也没有错)。
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 版本中更改,因此您可能希望在它被记录之前很少使用它。
从react模式:
React 组件中的大多数依赖注入的解决方案都是基于 context 的。我认为了解幕后发生的事情很好。在撰写本文时,构建 React 应用程序的最流行方法之一涉及 Redux。著名的 connect 函数和那里的 Provider 使用上下文。
从react文档:
上下文是一项高级和实验性的功能。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 容器的主要优点是我们没有使用上下文!
您可以在此处了解更多信息。
我真的不喜欢使用contexts,因为它仍然是 react 的一个实验性功能并且有点笨重。我也看过类似的 DI 框架,react-di但它要求每个组件都知道 DI 框架注入依赖项的方式(即知道依赖项在this.props.di对象中。)。
如果我们排除上下文,则将某些内容注入 React 组件的规范方法是使用 props。当您运行时React.createElement,即为每个 jsx 标签注入props。该React.createElement函数接受一个组件、一些props和一些子元素,并返回一个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
);
};
};
返回的组件可以注入到一个 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系统即可。所以组件不需要知道你在使用依赖注入或者你是怎么做的,他们只关心他们收到了什么props。