Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions docs/api/presenter.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,24 @@ planets from the Microcosm instance provided to it via the `repo`
prop. This is available as state, which the Presenter can send into a
child component.

### Listening to all state changes

While we do not recommend it for large projects, some times it's simply easier
to subscribe to all repo changes. `viewModel` can also return a function, which
will be called with state:

```javascript
class PlanetsPresenter extends Presenter {
viewModel(props) {
return state => state
}

render() {
return <p>{ this.state.planets.join(', ') }</p>
}
}
```

## Receiving Intents

Though explicit, passing event callbacks down through a deep component
Expand Down
16 changes: 14 additions & 2 deletions src/addons/presenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,14 @@ export default class Presenter extends Component {
* @private
*/
_updatePropMap (props) {
this.propMap = this.viewModel(props)
this.propMap = this.viewModel ? this.viewModel(props) : {}

if (this.repo && this.propMap === this.repo.state) {
console.warn("The view model for this presenter returned repo.state. " +
"This method onlys run when a presenter is given new properties. " +
"If you would like to subscribe to all state changes, return a " +
"function like: `(state) => state`.")
}
}

/**
Expand All @@ -125,9 +132,14 @@ export default class Presenter extends Component {
* @private
*/
_getState () {
const nextState = {}
const repoState = this._getRepoState()

if (typeof this.propMap === 'function') {
return this.propMap(repoState)
}

const nextState = {}

for (let key in this.propMap) {
const entry = this.propMap[key]

Expand Down
34 changes: 34 additions & 0 deletions test/addons/presenter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,37 @@ test('calling setState in setup does not raise a warning', t => {

console.restore()
})

test('warns when setState in setup does not raise a warning', t => {
class MyPresenter extends Presenter {
viewModel() {
return this.repo.state
}
render() {
return <p>Test</p>
}
}

console.record()

mount(<MyPresenter repo={ new Microcosm() } />)

t.regex(console.last('warn'), /The view model for this presenter returned repo\.state/i)

console.restore()
})

test('allows functions to return from viewModel', t => {
class MyPresenter extends Presenter {
viewModel() {
return state => state
}
render() {
return <p>Test</p>
}
}

const el = mount(<MyPresenter repo={new Microcosm()} />)

t.is(el.state(), el.instance().repo.state)
})
6 changes: 5 additions & 1 deletion test/helpers/console.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@ export default {
record() {
for (let key in messages) {
originals[key] = console[key]
console[key] = (...args) => messages[key].push([args])
console[key] = (...args) => messages[key].push([args.join(' ')])
}
},

last(key) {
return messages[key][messages[key].length - 1]
},

count(key) {
if (key in messages === false) {
throw new Error(`console.${key} is not tracked. Please add it to "${ __filename }."`)
Expand Down