Skip to content

Commit

Permalink
Introduce thunks (#305)
Browse files Browse the repository at this point in the history
Thunks allow users to return a function from an action,
then we will call such function passing the same update
function we use enqueue repaints/renders. 

When using a thunk, it's now up to the user to initiate an 
update or not.
  • Loading branch information
Swizz authored and Jorge Bucaran committed Jul 24, 2017
1 parent 9939fd3 commit 54e7dc3
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 3 deletions.
15 changes: 13 additions & 2 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ export function app(app) {

return emit

function update(withState) {
if (withState != null) {
repaint((state = merge(state, emit("update", withState))))
}
}

function repaint() {
if (!locked) {
requestAnimationFrame(render, (locked = !locked))
Expand Down Expand Up @@ -81,8 +87,13 @@ export function app(app) {
}).data
)

if (result != null && result.then == null) {
repaint((state = merge(state, emit("update", result))))
if (result == null) {
} else if (typeof result == "function") {
result = result(update)
} else if (typeof result.then == "function") {
result.then(update)
} else {
update(result)
}

return result
Expand Down
70 changes: 69 additions & 1 deletion test/actions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ test("update the state async", done => {
})
})

test("update the state async using a promise", done => {
test("update the state async using a promise with handler", done => {
app({
state: 1,
view: state => h("div", {}, state),
Expand All @@ -68,6 +68,74 @@ test("update the state async using a promise", done => {
})
})

test("update the state async using a thunk", done => {
app({
state: 1,
view: state => h("div", {}, state),
actions: {
delay: state => new Promise(resolve => setTimeout(() => resolve(), 20)),
delayAndChange: (state, actions, data) => (update) => {
actions.delay().then(() => {
update(state + data)

setTimeout(() => {
expect(document.body.innerHTML).toBe(`<div>${state + data}</div>`)
done()
})
})
}
},
events: {
init: (state, actions) => actions.delayAndChange(100)
}
})
})

test("update the state async using a promise", done => {
app({
state: 1,
view: state => h("div", {}, state),
actions: {
delay: state => new Promise(resolve => setTimeout(() => resolve(), 20)),
delayAndChange: (state, actions, data) => {
return actions.delay().then(() => {
return state + data
})
}
},
events: {
init: (state, actions) => actions.delayAndChange(100),
render: () => {
setTimeout(() => {
expect(document.body.innerHTML).toBe(`<div>101</div>`)
done()
})
}
}
})
})

test("update a state using then sync", done => {
app({
state: {
then: 1
},
view: state => h("div", null, state.then),
actions: {
add: state => ({ then: state.then + 1 })
},
events: {
init: (state, actions) => {
actions.add()
},
loaded: () => {
expect(document.body.innerHTML).toBe(`<div>2</div>`)
done()
}
}
})
})

test("namespaced/nested actions", () => {
app({
state: true,
Expand Down

0 comments on commit 54e7dc3

Please sign in to comment.