Skip to content

Commit

Permalink
add basic differ
Browse files Browse the repository at this point in the history
  • Loading branch information
bcherny committed Dec 3, 2017
1 parent 303fe88 commit 0644608
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 5 deletions.
32 changes: 27 additions & 5 deletions src/react.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,29 @@ export function connect<Actions extends object>(store: Store<Actions>) {
Component: React.ComponentType<Props>
) {

let state: IDisposable[]
let state: IDisposable[][]

return class extends React.Component<Omit<Props, 'store'>> {
componentDidMount() {
state = listenOn.map(key =>
store.on(key).subscribe(() => this.forceUpdate())
)
state = listenOn.map(key => {
let ignore = false
return [
store.before(key).subscribe(({ previousValue, value }) => {
if (equals(previousValue, value)) {
return ignore = true
}
}),
store.on(key).subscribe(() => {
if (ignore) {
return ignore = false
}
this.forceUpdate()
})
]
})
}
componentWillUnmount() {
state.forEach(_ => _.dispose())
state.forEach(_ => _.forEach(_ => _.dispose()))
}
render() {
return <Component {...this.props} store={store} />
Expand All @@ -30,3 +43,12 @@ export function connect<Actions extends object>(store: Store<Actions>) {
}
}
}

/**
* TODO: Avoid diffing by passing individual values into a React component
* rather than the whole `store`, and letting React and `shouldComponentUpdate`
* handle diffing for us.
*/
function equals<T>(a: T, b: T): boolean {
return a === b
}
23 changes: 23 additions & 0 deletions test/stateful.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,26 @@ withElement(MyComponentWithLens, _ => {
Simulate.click(_.querySelector('button')!)
})
)

test('[stateful] it should only re-render if something actually changed', t => {

let renderCount = 0
let A = connect(store)()(
class extends React.Component<Props> {
render() {
renderCount++
return <div>
{this.props.store.get('isTrue') ? 'True' : 'False'}
<button onClick={() => this.props.store.set('isTrue')(this.props.store.get('isTrue'))}>Update</button>
</div>
}
}
)

withElement(A, _ => {
Simulate.click(_.querySelector('button')!)
Simulate.click(_.querySelector('button')!)
Simulate.click(_.querySelector('button')!)
t.is(renderCount, 1)
})
})
19 changes: 19 additions & 0 deletions test/stateless.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,22 @@ test('[stateless] it should call .on().subscribe() with the current value', t =>
Simulate.click(_.querySelector('button')!)
})
)

test('[stateless] it should only re-render if something actually changed', t => {

let renderCount = 0
let A = connect(store)('isTrue')(({ store }) => {
renderCount++
return <div>
{store.get('isTrue') ? 'True' : 'False'}
<button onClick={() => store.set('isTrue')(store.get('isTrue'))}>Update</button>
</div>
})

withElement(A, _ => {
Simulate.click(_.querySelector('button')!)
Simulate.click(_.querySelector('button')!)
Simulate.click(_.querySelector('button')!)
t.is(renderCount, 1)
})
})

0 comments on commit 0644608

Please sign in to comment.