Skip to content

Commit

Permalink
Handle deferred services in useIsXStateTransitionAvailable()
Browse files Browse the repository at this point in the history
  • Loading branch information
VanTanev committed Aug 18, 2021
1 parent b9892c9 commit 312622c
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 2 deletions.
17 changes: 15 additions & 2 deletions src/react/useIsXStateTransitionAvailable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,27 @@ export function useIsXStateTransitionAvailable<
| (ActorRef<TEvent> & { machine?: StateMachine<any, any, TEvent, any> }),
event: TEventType | TEvent,
): boolean {
if (!service.machine) {
if (
// Machines invoked as services will be initially deferred:
// https://github.com/statelyai/xstate/blob/5da8724bb6c4dada5d6e8cc61e36c7e2c771838b/packages/core/src/Actor.ts#L74-L94
//
// Because we don't know what a deferred service will initialize to,
// we shouldn't throw if it doesn't have a "machine" property
//
// @ts-ignore
!service.deferred &&
!service.machine
) {
throw new Error(
'The service given to useIsXStateTransitionAvailable() must be a state machine instance.',
);
}

return useSelector<typeof service, boolean>(
service,
useCallback(state => !!service.machine!.transition(state, event).changed, [service, event]),
useCallback(
state => !!service.machine && !!service.machine!.transition(state, event).changed,
[service, event],
),
);
}
13 changes: 13 additions & 0 deletions test/react/useIsXStateTransitionAvailable.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { renderHook } from '@testing-library/react-hooks';
import { useIsXStateTransitionAvailable } from '../../src/react/useIsXStateTransitionAvailable';
import { createMachine, interpret, Interpreter } from 'xstate';
import { useActor } from '@xstate/react';

describe('useIsXStateTransitionAvailable', () => {
type TContext = {};
Expand Down Expand Up @@ -37,6 +38,10 @@ describe('useIsXStateTransitionAvailable', () => {
},
},
},
invoke: {
id: 'child',
src: createMachine({}),
},
}),
);
});
Expand Down Expand Up @@ -82,4 +87,12 @@ describe('useIsXStateTransitionAvailable', () => {
const { result } = renderHook(() => useIsXStateTransitionAvailable({} as any, ''));
expect(result.error?.message).toMatch('must be a state machine instance');
});

it('works with invoked child machines', () => {
const { result } = renderHook(() => {
const [state] = useActor(service);
return useIsXStateTransitionAvailable(state.children['child'], 'I_DONT_EXIST');
});
expect(result.current).toBe(false);
});
});

0 comments on commit 312622c

Please sign in to comment.