在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