diff --git a/src/hooks/__tests__/useIsActive.test.tsx b/src/hooks/__tests__/useIsActive.test.tsx index 168b4841..1eb05e7f 100644 --- a/src/hooks/__tests__/useIsActive.test.tsx +++ b/src/hooks/__tests__/useIsActive.test.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { RawParams } from '@uirouter/core'; import { makeTestRouter } from '../../__tests__/util'; +import { UIView } from '../../components'; import { useIsActive } from '../useIsActive'; const state1 = { name: 'state1', url: '/state1' }; @@ -52,6 +53,24 @@ describe('useIsActive', () => { expect(wrapper.find('div').props().className).toBe('notactive'); }); + it('works with relative states', async () => { + const parent = { name: 'parent', component: () => }; + const child = { name: 'parent.child', component: () =>
}; + router.stateRegistry.register(parent); + router.stateRegistry.register(child); + await routerGo('parent'); + const wrapper = mountInRouter(); + expect(wrapper.find('div').props().className).toBe('notactive'); + + await routerGo('parent.child'); + expect( + wrapper + .update() + .find('div') + .props().className + ).toBe('yesactive'); + }); + it('updates when the desired state changes', async () => { await routerGo('state2'); const wrapper = mountInRouter(); diff --git a/src/hooks/useIsActive.ts b/src/hooks/useIsActive.ts index d29d8557..3dc8c573 100644 --- a/src/hooks/useIsActive.ts +++ b/src/hooks/useIsActive.ts @@ -1,28 +1,39 @@ -import { StateService } from '@uirouter/core'; +import { StateDeclaration } from '@uirouter/core'; import { useEffect, useMemo, useState } from 'react'; +import { UIRouterReact } from '../core'; import { useDeepObjectDiff } from './useDeepObjectDiff'; import { useOnStateChanged } from './useOnStateChanged'; import { useRouter } from './useRouter'; +import { useViewContextState } from './useViewContextState'; -function checkIfActive(stateService: StateService, stateName: string, params: object, exact: boolean) { - return exact ? stateService.is(stateName, params) : stateService.includes(stateName, params); +function checkIfActive( + router: UIRouterReact, + stateName: string, + params: object, + relative: StateDeclaration, + exact: boolean +) { + return exact + ? router.stateService.is(stateName, params, { relative }) + : router.stateService.includes(stateName, params, { relative }); } export function useIsActive(stateName: string, params = null, exact = false) { - const { stateService } = useRouter(); + const router = useRouter(); + const relative = useViewContextState(router); // Don't re-compute initialIsActive on every render - const initialIsActive = useMemo(() => checkIfActive(stateService, stateName, params, exact), []); + const initialIsActive = useMemo(() => checkIfActive(router, stateName, params, relative, exact), []); const [isActive, setIsActive] = useState(initialIsActive); const checkIfActiveChanged = () => { - const newIsActive = checkIfActive(stateService, stateName, params, exact); + const newIsActive = checkIfActive(router, stateName, params, relative, exact); if (newIsActive !== isActive) { setIsActive(newIsActive); } }; useOnStateChanged(checkIfActiveChanged); - useEffect(checkIfActiveChanged, [stateService, stateName, useDeepObjectDiff(params), exact]); + useEffect(checkIfActiveChanged, [router, stateName, useDeepObjectDiff(params), exact]); return isActive; }