• 依赖注入
    • 参考资料:

    依赖注入

    在React中,想做依赖注入(Dependency Injection)其实相当简单。请看下面这个例子:

    1. // Title.jsx
    2. export default function Title(props) {
    3. return <h1>{ props.title }</h1>;
    4. }
    1. // Header.jsx
    2. import Title from './Title.jsx';
    3. export default function Header() {
    4. return (
    5. <header>
    6. <Title />
    7. </header>
    8. );
    9. }
    1. // App.jsx
    2. import Header from './Header.jsx';
    3. class App extends React.Component {
    4. constructor(props) {
    5. super(props);
    6. this.state = { title: 'React Dependency Injection' };
    7. }
    8. render() {
    9. return <Header />;
    10. }
    11. }

    试想,我们想把”React Dependency Injection”这个字符串传到我们的Title组件里面去。比较直观的方法是把这个字符串作为props传入Header组件,然后Header组件将这个字符串作为props传入Title组件。
    在只有三个组件相互嵌套的情况下,上面的这种解决方式似乎能满足我们的需要。但是设想一下,随着组件数量的增加以及组件嵌套层次的加深,许多的组件都需要接收该组件本身并不需要关心的props,然后且简单地传递给子组件。直观上来看,上面的这种方法在这种情况下,似乎就不太适用了。

    不过不用担心,事实上我们还有很多方法能实现依赖的注入,其中之一就是高阶组件(high-order component)。

    1. // inject.jsx
    2. var title = 'React Dependency Injection';
    3. export default function inject(Component) {
    4. return class Injector extends React.Component {
    5. render() {
    6. return (
    7. <Component
    8. {...this.state}
    9. {...this.props}
    10. title={ title }
    11. />
    12. )
    13. }
    14. };
    15. }
    1. // Title.jsx
    2. export default function Title(props) {
    3. return <h1>{ props.title }</h1>;
    4. }
    1. // Header.jsx
    2. import inject from './inject.jsx';
    3. import Title from './Title.jsx';
    4. var EnhancedTitle = inject(Title);
    5. export default function Header() {
    6. return (
    7. <header>
    8. <EnhancedTitle />
    9. </header>
    10. );
    11. }

    在上面这种实现中,title这个字符串作为我们的数据没有被注入到整个的组件树中。相反,我们的数据只传递给了需要关注这个数据的组件。
    这种实现看上去比上面优雅了很多,但事实上并没有完全解决我们的问题。
    我们将title这个字符串通过inject这个高阶组件注入了进去,但是如果我的title字符串只能在我的Header组件这个层级获得呢?那么是不是意味着我还需要再从Header组件传递给inject组件呢?

    这是一个实际可能会发生的问题,为了解决这个问题,接下来需要介绍一下React的Context API。
    在React框架中,存在着context这样一个概念。context有点类似与事件总线(Event Bus),是一个无论在哪都可以访问的对象。不同的是,但是在context里面维持的全部都是我们的数据而非事件。context贯穿于整个组件树中,所有的组件都可以访问context。

    使用方法

    1. var context = { title: 'React in patterns' };
    2. class App extends React.Component {
    3. getChildContext() {
    4. return context;
    5. }
    6. // ...
    7. }
    8. App.childContextTypes = {
    9. title: PropTypes.string
    10. };

    A place where we need data

    1. class Inject extends React.Component {
    2. render() {
    3. var title = this.context.title;
    4. // ...
    5. }
    6. }
    7. Inject.contextTypes = {
    8. title: PropTypes.string
    9. };

    需要注意的是,在最新的React官方文档中,Context已经不太被官方推荐使用了。Why Not To Use Context

    参考资料:

    • What is Dependency Injection?
    • The Basics of Dependency Injection
    • Dependency injection in JavaScript
    • DI In React