Right now our codebase has a bunch of Provider
components at the top level which facilitate Higher-Order-Component based dep injection. Basically we're using #3. Is this good? Is this bad? Relay modern seems to be moving to a style more like #4, and there were some positive opinions about this it seems.
Personally, I really really don't like #4 because it is type-hostile (we need to type the props that are cloned in as optional or typescript will freak out when we don't pass them) and because it just seems the least explicit to me. That said, it seems there are some other strong opinions on this.
//MyComponent.ts
import thingleton from '../../../wherever';
import otherThingleton from '../../../wherever';
function MyComponent(){
//stuff that uses thingleton and otherThingleton
}
//consumer.ts
<MyComponent> // no injection required
//test.ts
import thingleton from '../../../wherever';
import otherThingleton from '../../../wherever';
before(() => {
someCodeThatStubsAllTheFunctionsOnTheActualSingletons()
})
it('is cool') {
mount(<MyComponent />)
}
//MyComponent.ts
@inject('thing', 'other-thing')
function MyComponent({thing, otherThing}: {thing: Thing, otherThing: OtherThing}){
....
}
//consumer.ts
<MyComponent /> // this has those dependencies because we used inject
//test.ts
import {mockThing, mockOtherThing} from 'test/mocks';
it('is cool') {
mount(<MyComponent thing={mockThing} otherThing={mockOtherTHing} />)
}
//MyComponent.ts
@withThing
@withOtherThing
function MyComponent({thing, otherThing}: {thing: Thing, otherThing: OtherThing}){
....
}
//consumer.ts
<MyComponent /> // this has those dependencies because we used inject
//test.ts
import {mockThing, mockOtherThing} from 'test/mocks';
it('is cool') {
mount(<MyComponent thing={mockThing} otherThing={mockOtherTHing} />)
}
//MyComponent.ts
function MyComponent({thing, otherThing}: {thing: Thing, otherThing: OtherThing}){
....
}
//consumer.ts
<ThingInjector><MyComponent /></ThingInjector>
//test.ts
import {mockThing, mockOtherThing} from 'test/mocks';
it('is cool') {
mount(<MyComponent thing={mockThing} otherThing={mockOtherTHing} />)
}
//MyComponent.ts
function MyComponent({thing, otherThing}: {thing: Thing, otherThing: OtherThing}){
....
}
//consumer.ts
<ThingInjector
children={(dependencies) => <MyComponent {...dependencies}/>}
/>
//test.ts
import {mockThing, mockOtherThing} from 'test/mocks';
it('is cool') {
mount(<MyComponent thing={mockThing} otherThing={mockOtherTHing} />)
}