Package Exports
- deviation
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (deviation) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme

Install
You can install Deviation by either using PNPM, Yarn or NPM:
# PNPM
$ pnpm add deviation
# Yarn
$ yarn add deviation
# NPM
$ npm add deviation
What is Deviation?
Deviation is a library that trying to simulate Angular DI model into React using RxJS and React Context API. Here is our example:
import { Deviation, Store, Inject } from 'deviation'
export class TodoStore extends Store {
state = {
todos: []
}
addTodo(newTodo) {
this.setState(({ todos }) => ({
todos: todos.concat([newTodo])
}))
}
}
ReactDOM.render(
<Deviation providers={[TodoStore]}>
<TodoApp />
</Deviation>,
document.querySelector('#root')
)
@Inject({
todoStore: TodoStore
})
export class TodoApp extends React.Component {
handleSubmit = event => {
this.props.todoStore.addTodo(event.target.value)
}
render() {
const { todoStore } = this.props
return (
<div>
<ul>
{todoStore.state.todos.map(todo => (
<li>{todo}</li>
))}
</ul>
<div>
<label for="new-todo">New Todo:</label>
<input
name="new-todo"
type="input"
onKeyDown={enter(this.handleSubmit)}
/>
</div>
</div>
)
}
}
Store DI
We can also use DI to inject directly store into store:
@Inject({
balanceStore: BalanceStore
})
export class ContractStore extends Store {}
Remember, stores are injected in order. For example:
ReactDOM.render(
<Deviation providers={[BalanceStore, ContractStore]}>
<TodoApp />
</Deviation>,
document.querySelector('#root')
)
In this example, BalanceStore
will be injected before ContractStore
. However, if ContractStore
is placed behind BalanceStore
in the list of providers: [BalanceStore, ContractStore]
, then after ContractStore
constructor is called and before storeDidMount
is called, BalanceStore
will be injected into ContractStore
.
Lazy DI and Cyclic DI
Sometimes, you may need Cyclic Dependency Injection. Deviation also provides you with Cyclic DI:
@Inject({
storeA: () => StoreA
})
export class StoreB extends Store {
get storeA() {
return this.props.storeA
}
}
@Inject({
storeB: () => StoreB
})
export class StoreA extends Store {
get storeB() {
return this.props.storeB
}
}
Testing
To test on a single Store method is easy. You just have to stub or spy on that method:
export class PhoneStore extends Store {
makeAPhoneCall() {}
}
const spy = sinon.spy(PhoneStore.prototype.makeAPhoneCall)
expect(spy.calledOnce).to.be.true
However, we are more likely to extract the store instance from the providers. In that case, we can create a store extractor that can help us to extract any store instance from Deviation
:
import { createStoreExtractor } from 'deviation'
const Extractor = createStoreExtractor()
mount(
<Deviation providers={[PhoneStore, Extractor]}>
<AppComponent />
</Deviation>
)
const phoneStore = Extractor.getStore(PhoneStore)