Skip to content

Commit

Permalink
support async updaters as well as actions
Browse files Browse the repository at this point in the history
  • Loading branch information
apaleslimghost committed Nov 5, 2018
1 parent 20f73c4 commit 55b226c
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 19 deletions.
17 changes: 17 additions & 0 deletions components/x-interaction/__tests__/x-interaction.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,23 @@ describe('x-interaction', () => {
).toBe(10);
});

it('should update props of base using async updater function from action', async () => {
const Base = () => null;
const Wrapped = withActions({
foo: () => async ({bar}) => ({ bar: bar + 5 }),
})(Base);

const target = mount(<Wrapped bar={5} />);

await target.find(Base).prop('actions').foo();
target.update();

expect(
target.find(Base).prop('bar')
).toBe(10);
});


it('should wait for promises and apply resolved state updates', async () => {
const Base = () => null;
const Wrapped = withActions({
Expand Down
38 changes: 19 additions & 19 deletions components/x-interaction/src/InteractionClass.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,32 @@ export class InteractionClass extends Component {
inFlight: 0,
};

this.actions = mapValues(props.actions, (func) => (...args) => {
this.actions = mapValues(props.actions, (func) => async (...args) => {
// mark as loading one microtask later. if the action is synchronous then
// setting loading back to false will happen in the same microtask and no
// additional render will be scheduled.
Promise.resolve().then(() => {
this.setState(({ inFlight }) => ({ inFlight: inFlight + 1 }));
});

return Promise.resolve(func(...args)).then((next) => {
const updater = typeof next === 'function'
? ({state}) => ({state: Object.assign(
state,
next(Object.assign(
{},
props.initialState,
state
))
)})
: ({state}) => ({state: Object.assign(state, next)});

return new Promise(resolve =>
this.setState(updater, () => (
this.setState(({ inFlight }) => ({ inFlight: inFlight - 1 }), resolve)
))
);
});
const stateUpdate = await Promise.resolve(func(...args));

const nextState = typeof stateUpdate === 'function'
? Object.assign(
this.state.state,
await Promise.resolve(stateUpdate(Object.assign(
{},
props.initialState,
this.state.state
)))
)
: Object.assign(this.state.state, stateUpdate);

return new Promise(resolve =>
this.setState({state: nextState}, () => (
this.setState(({ inFlight }) => ({ inFlight: inFlight - 1 }), resolve)
))
);
});
}

Expand Down

0 comments on commit 55b226c

Please sign in to comment.