依赖注入

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

// Title.jsx
export default function Title(props) {
  return <h1>{ props.title }</h1>;
}
// Header.jsx
import Title from './Title.jsx';
export default function Header() {
  return (
    <header>
      <Title />
    </header>
  );
}
// App.jsx
import Header from './Header.jsx';
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { title: 'React Dependency Injection' };
  }
  render() {
    return <Header />;
  }
}

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

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

// inject.jsx
var title = 'React Dependency Injection';
export default function inject(Component) {
  return class Injector extends React.Component {
    render() {
      return (
        <Component
          {...this.state}
          {...this.props}
          title={ title }
        />
      )
    }
  };
}
// Title.jsx
export default function Title(props) {
  return <h1>{ props.title }</h1>;
}
// Header.jsx
import inject from './inject.jsx';
import Title from './Title.jsx';

var EnhancedTitle = inject(Title);
export default function Header() {
  return (
    <header>
      <EnhancedTitle />
    </header>
  );
}

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

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

使用方法

var context = { title: 'React in patterns' };
class App extends React.Component {
  getChildContext() {
    return context;
  }
  // ...
}

App.childContextTypes = {
  title: PropTypes.string
};

A place where we need data

class Inject extends React.Component {
  render() {
    var title = this.context.title;
  // ...
  }
}
Inject.contextTypes = {
  title: PropTypes.string
};

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

参考资料:

results matching ""

    No results matching ""