-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
State: Type route path & query #55315
base: trunk
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* eslint-disable jsdoc/require-param */ | ||
/** | ||
* Internal dependencies | ||
*/ | ||
import 'calypso/state/ui/init'; | ||
import { ROUTE_SET, ROUTE_CLEAR_LAST_NON_EDITOR } from 'calypso/state/action-types'; | ||
import { RouteClearActionCreator, RouteSetActionCreator } from 'calypso/state/route/types'; | ||
|
||
/** | ||
* Returns an action object signalling that the current route is to be changed | ||
*/ | ||
export const setRoute: RouteSetActionCreator = ( path, query = {} ) => { | ||
return { | ||
type: ROUTE_SET, | ||
path, | ||
query, | ||
}; | ||
}; | ||
|
||
/** | ||
* Action to forget what the last non-editor route was. | ||
*/ | ||
export const clearLastNonEditorRoute: RouteClearActionCreator = () => { | ||
return { | ||
type: ROUTE_CLEAR_LAST_NON_EDITOR, | ||
}; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,10 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { Reducer, AnyAction } from 'redux'; | ||
/** | ||
* Internal dependencies | ||
*/ | ||
import { ROUTE_CLEAR_LAST_NON_EDITOR, ROUTE_SET } from 'calypso/state/action-types'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This PR adds a |
||
|
||
/** | ||
|
@@ -8,7 +15,7 @@ import { ROUTE_CLEAR_LAST_NON_EDITOR, ROUTE_SET } from 'calypso/state/action-typ | |
*/ | ||
const editorPattern = /^\/(block-editor|page[^s]|post[^s])/; | ||
|
||
export const lastNonEditorRouteReducer = ( state = '', action ) => { | ||
export const lastNonEditorRouteReducer: Reducer< string, AnyAction > = ( state = '', action ) => { | ||
const { path, type } = action; | ||
switch ( type ) { | ||
case ROUTE_SET: | ||
|
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { isEqual, omit } from 'lodash'; | ||
import { Reducer, AnyAction } from 'redux'; | ||
/** | ||
* Internal dependencies | ||
*/ | ||
import { ROUTE_SET } from 'calypso/state/action-types'; | ||
import { Query, QueryState } from 'calypso/state/route/types'; | ||
|
||
const timestamped = ( query: Query ): Query => ( { | ||
...query, | ||
_timestamp: Date.now(), | ||
} ); | ||
|
||
const isEqualQuery = ( state: QueryState[ keyof QueryState ], query: Query ) => | ||
isEqual( omit( state, '_timestamp' ), omit( query, '_timestamp' ) ); | ||
|
||
const initialReducer = ( state: QueryState[ 'initial' ], query: Query ) => | ||
state === false ? timestamped( query ) : state; | ||
|
||
const currentReducer = ( state: QueryState[ 'current' ], query: Query ) => | ||
! isEqualQuery( state, query ) ? timestamped( query ) : state; | ||
|
||
const initialState: QueryState = { | ||
initial: false, | ||
current: false, | ||
previous: false, | ||
}; | ||
|
||
export const queryReducer: Reducer< QueryState, AnyAction > = ( state = initialState, action ) => { | ||
const { query, type } = action; | ||
switch ( type ) { | ||
case ROUTE_SET: | ||
return { | ||
initial: initialReducer( state.initial, query ), | ||
current: currentReducer( state.current, query ), | ||
previous: state.current === false ? false : state.current, | ||
}; | ||
} | ||
return state; | ||
}; | ||
|
||
export default queryReducer; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { Action } from 'redux'; | ||
|
||
export type Query = { | ||
[ key: string ]: string | number | undefined; | ||
_timestamp?: number; | ||
}; | ||
Comment on lines
+6
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not fun of this type. Hopefully, there's a way to express it differently. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The The Adding types reveals such hacks, like slapping non-query data on the |
||
|
||
export type QueryState = { | ||
initial: Query | false; | ||
current: Query | false; | ||
previous: Query | false; | ||
}; | ||
|
||
export type PathState = { | ||
initial: string; | ||
current: string; | ||
previous: string; | ||
}; | ||
|
||
export type RouteState = { | ||
lastNonEditorRoute: string; | ||
path: PathState; | ||
query: QueryState; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is also a |
||
}; | ||
|
||
export type RouteClearActionCreator = () => Action; | ||
|
||
export type RouteSetActionCreator = ( path: string, query: Query ) => Action; |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* eslint-disable jsdoc/require-param */ | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import 'calypso/state/route/init'; | ||
|
||
/** | ||
* Type dependencies | ||
*/ | ||
import type { Query } from 'calypso/state/route/types'; | ||
import type { IAppState } from 'calypso/state/types'; | ||
|
||
/** | ||
* Gets the last query parameters set by a ROUTE_SET action | ||
* | ||
* TODO: We would be better off not conditioning with null here. | ||
* Kept for backwards compatibility in case any null checks. | ||
* Investigate and refactor. | ||
*/ | ||
export function getCurrentQueryArguments( state: IAppState ): Query | false | null { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The return type should be just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel the selector could just return whatever This makes sense to me in the following way:
Of course, trade-offs e.g. a derived state selector will ultimately provide some sort of default, which they'd be responsible for defining anyhow. So the alternative (what you mention I think) might just be better e.g. selectors always defining and returning the default values. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I think the const EMPTY_QUERY = {};
const initialState = {
initial: EMPTY_QUERY,
current: EMPTY_QUERY,
previous: EMPTY_QUERY,
}; And the reducer for initial = state.initial === EMPTY_QUERY ? action.query : state.initial to set the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's perfect. Thanks! We'll take this path. |
||
return state?.route?.query?.current || null; | ||
} | ||
|
||
export default getCurrentQueryArguments; |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* eslint-disable jsdoc/require-param */ | ||
/** | ||
* Internal dependencies | ||
*/ | ||
import 'calypso/state/route/init'; | ||
|
||
/** | ||
* Type dependencies | ||
*/ | ||
import type { IAppState } from 'calypso/state/types'; | ||
|
||
/** | ||
* Gets the last route set by a ROUTE_SET action | ||
* | ||
* TODO: We would be better off not conditioning with null here. | ||
* Kept for backwards compatibility in case any null checks. | ||
* Investigate and refactor. | ||
*/ | ||
export function getCurrentRoute( | ||
state: IAppState | ||
): IAppState[ 'route' ][ 'path' ][ 'current' ] | null { | ||
return state?.route?.path?.current || null; | ||
} | ||
|
||
export default getCurrentRoute; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,13 @@ | ||
import { DefaultRootState } from 'react-redux'; | ||
import { IMarketplaceState } from 'calypso/state/marketplace/types'; | ||
import { IPluginsState } from 'calypso/state/plugins/reducer'; | ||
import { RouteState } from 'calypso/state/route/types'; | ||
|
||
/** | ||
* This global app state is currently incomplete and should be completed as each state slice becomes typed | ||
* */ | ||
export interface IAppState extends DefaultRootState { | ||
plugins: IPluginsState; | ||
marketplace: IMarketplaceState; | ||
route: RouteState; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't look like an improvement. Just
const { dev, view } = useSelector( ... )
should work. If it doesn't, there's something wrong with the types and they should be fixed. Calling the selector twice and introducing a new usage of Lodash is not good.