反应依赖注入或类似的?
React dependency injection or similar?
在Angular.js中可以使用依赖注入。我做了一些浏览,但无法找到它的实现。 React 有类似的东西吗?
React 有 IoC,但没有任何像 Angular 这样的 DI 容器的概念。也就是说,不是让容器知道如何创建对象并传递依赖项,而是在实例化组件时通过将 props 传递给组件来显式传递它们(如 <MyComponent items={this.state.items} />
)。
尽管在 React 世界中将依赖项作为 props 传递并不是很常见。 Props 主要用于将数据传递给组件而不是 services/stores。但是没有什么可以阻止您将 services/stores 甚至组件作为道具传递(当然没有错)。
React 有一个 context
的概念,它是整个组件树的共享对象。因此顶级组件可以说它的子树的上下文有一个对象,其中包含 UserStore、MessageStore 等。组件层次结构中更靠下的组件然后可以说它想要访问其上下文中的 UserStore。也就是说,该组件可以访问 UserStore,而无需显式地将其从顶部组件向下传递到底部,并且请求它的组件不知道它是如何 created/passed 的。
它具有 DI 容器的优势,您可以在其中集中创建可以向下传递的对象。这是一个很好的上下文介绍:https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html
上下文仍然是 React 的一个未记录的特性,这意味着它 API 可以在 React 的任何即将发布的版本中改变,所以在它被记录之前你可能想要稀疏地使用它。
我不太喜欢使用 contexts, since it's still an experimental feature of react and kind of bulky. I've also looked at DI frameworks like react-di
但它要求每个组件都知道 DI 框架注入依赖项的方式(即知道依赖项在 this.props.di
对象中。) .
如果我们排除上下文,将某些东西注入 React 组件的规范方法是使用 props。当你 运行 React.createElement
时,即为每个 jsx 标签注入道具。 React.createElement
函数接受一个组件、一些道具和一些子项以及 returns 个 React element。 IE。 (component, props, children) -> element
.
我制作了一个 createComponent
函数,其签名与 React.createElement
几乎相同,但 returns 是一个组件,即 (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} />;
}
Fiddle: https://jsfiddle.net/8971g8s5/3/
这样做的好处是 PropTypes
仍然可以很好地工作,因此每个组件都可以清楚地声明它想要什么样的属性。
另外,注入的接收端不需要依赖任何特殊的实现,只需要React的普通props系统即可。所以组件不需要知道你正在使用依赖注入或者你是如何使用它的,它们只关心它们接收到的 props。
Most of the solutions for dependency injection in React components are based on context. I think that it's good to know what happens under the hood. As the time of this writing one of the most popular ways for building React apps involves Redux. The famous connect function and the Provider there use the context.
并从反应 docs:
Context is an advanced and experimental feature. The API is likely to change in future releases.
Most applications will never need to use context. Especially if you are just getting started with React, you likely do not want to use context. Using context will make your code harder to understand because it makes the data flow less clear. It is similar to using global variables to pass state through your application.
If you have to use context, use it sparingly.
Regardless of whether you're building an application or a library, try to isolate your use of context to a small area and avoid using the context API directly when possible so that it's easier to upgrade when the API changes.
由于使用了 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。
在Angular.js中可以使用依赖注入。我做了一些浏览,但无法找到它的实现。 React 有类似的东西吗?
React 有 IoC,但没有任何像 Angular 这样的 DI 容器的概念。也就是说,不是让容器知道如何创建对象并传递依赖项,而是在实例化组件时通过将 props 传递给组件来显式传递它们(如 <MyComponent items={this.state.items} />
)。
尽管在 React 世界中将依赖项作为 props 传递并不是很常见。 Props 主要用于将数据传递给组件而不是 services/stores。但是没有什么可以阻止您将 services/stores 甚至组件作为道具传递(当然没有错)。
React 有一个 context
的概念,它是整个组件树的共享对象。因此顶级组件可以说它的子树的上下文有一个对象,其中包含 UserStore、MessageStore 等。组件层次结构中更靠下的组件然后可以说它想要访问其上下文中的 UserStore。也就是说,该组件可以访问 UserStore,而无需显式地将其从顶部组件向下传递到底部,并且请求它的组件不知道它是如何 created/passed 的。
它具有 DI 容器的优势,您可以在其中集中创建可以向下传递的对象。这是一个很好的上下文介绍:https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html
上下文仍然是 React 的一个未记录的特性,这意味着它 API 可以在 React 的任何即将发布的版本中改变,所以在它被记录之前你可能想要稀疏地使用它。
我不太喜欢使用 contexts, since it's still an experimental feature of react and kind of bulky. I've also looked at DI frameworks like react-di
但它要求每个组件都知道 DI 框架注入依赖项的方式(即知道依赖项在 this.props.di
对象中。) .
如果我们排除上下文,将某些东西注入 React 组件的规范方法是使用 props。当你 运行 React.createElement
时,即为每个 jsx 标签注入道具。 React.createElement
函数接受一个组件、一些道具和一些子项以及 returns 个 React element。 IE。 (component, props, children) -> element
.
我制作了一个 createComponent
函数,其签名与 React.createElement
几乎相同,但 returns 是一个组件,即 (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} />;
}
Fiddle: https://jsfiddle.net/8971g8s5/3/
这样做的好处是 PropTypes
仍然可以很好地工作,因此每个组件都可以清楚地声明它想要什么样的属性。
另外,注入的接收端不需要依赖任何特殊的实现,只需要React的普通props系统即可。所以组件不需要知道你正在使用依赖注入或者你是如何使用它的,它们只关心它们接收到的 props。
Most of the solutions for dependency injection in React components are based on context. I think that it's good to know what happens under the hood. As the time of this writing one of the most popular ways for building React apps involves Redux. The famous connect function and the Provider there use the context.
并从反应 docs:
Context is an advanced and experimental feature. The API is likely to change in future releases.
Most applications will never need to use context. Especially if you are just getting started with React, you likely do not want to use context. Using context will make your code harder to understand because it makes the data flow less clear. It is similar to using global variables to pass state through your application.
If you have to use context, use it sparingly.
Regardless of whether you're building an application or a library, try to isolate your use of context to a small area and avoid using the context API directly when possible so that it's easier to upgrade when the API changes.
由于使用了 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。