diff --git a/src/Get.tsx b/src/Get.tsx index 31de7321..12fb9086 100644 --- a/src/Get.tsx +++ b/src/Get.tsx @@ -7,29 +7,29 @@ import RestfulReactProvider, { RestfulReactConsumer, RestfulReactProviderProps } */ export type ResolveFunction = (data: any) => T; -export interface GetDataError { +export interface GetDataError { message: string; - data: S; + data: TError; } /** * An enumeration of states that a fetchable * view could possibly have. */ -export interface States { +export interface States { /** Is our view currently loading? */ loading: boolean; /** Do we have an error in the view? */ - error?: GetComponentState["error"]; + error?: GetComponentState["error"]; } /** * An interface of actions that can be performed * within Get */ -export interface Actions { +export interface Actions { /** Refetches the same path */ - refetch: () => Promise; + refetch: () => Promise; } /** @@ -46,7 +46,7 @@ export interface Meta { /** * Props for the component. */ -export interface GetComponentProps { +export interface GetComponentProps { /** * The path at which to request data, * typically composed by parent Gets or the RestfulProvider. @@ -59,14 +59,14 @@ export interface GetComponentProps { * @param data - data returned from the request. * @param actions - a key/value map of HTTP verbs, aliasing destroy to DELETE. */ - children: (data: T | null, states: States, actions: Actions, meta: Meta) => React.ReactNode; + children: (data: TData | null, states: States, actions: Actions, meta: Meta) => React.ReactNode; /** Options passed into the fetch call. */ requestOptions?: RestfulReactProviderProps["requestOptions"]; /** * A function to resolve data return from the backend, most typically * used when the backend response needs to be adapted in some way. */ - resolve?: ResolveFunction; + resolve?: ResolveFunction; /** * Should we wait until we have data before rendering? * This is useful in cases where data is available too quickly @@ -90,7 +90,7 @@ export interface GetComponentProps { * are implementation details and should be * hidden from any consumers. */ -export interface GetComponentState { +export interface GetComponentState { data: T | null; response: Response | null; error: GetDataError | null; @@ -102,15 +102,18 @@ export interface GetComponentState { * is a named class because it is useful in * debugging. */ -class ContextlessGet extends React.Component, Readonly>> { - public readonly state: Readonly> = { +class ContextlessGet extends React.Component< + GetComponentProps, + Readonly> +> { + public readonly state: Readonly> = { data: null, // Means we don't _yet_ have data. response: null, loading: !this.props.lazy, error: null, }; - public static defaultProps: Partial> = { + public static defaultProps = { resolve: (unresolvedData: any) => unresolvedData, }; @@ -120,7 +123,7 @@ class ContextlessGet extends React.Component, Readonly) { + public componentDidUpdate(prevProps: GetComponentProps) { // If the path or base prop changes, refetch! const { path, base } = this.props; if (prevProps.path !== path || prevProps.base !== base) { @@ -168,7 +171,7 @@ class ContextlessGet extends React.Component, Readonly extends React.Component, Readonly(props: GetComponentProps) { +function Get(props: GetComponentProps) { return ( {contextProps => ( diff --git a/src/Mutate.tsx b/src/Mutate.tsx index 5c563653..f5153807 100644 --- a/src/Mutate.tsx +++ b/src/Mutate.tsx @@ -6,11 +6,11 @@ import { GetComponentState } from "./Get"; * An enumeration of states that a fetchable * view could possibly have. */ -export interface States { +export interface States { /** Is our view currently loading? */ loading: boolean; /** Do we have an error in the view? */ - error?: GetComponentState["error"]; + error?: GetComponentState["error"]; } /** @@ -47,7 +47,7 @@ export interface MutateComponentCommonProps { requestOptions?: RestfulReactProviderProps["requestOptions"]; } -export interface MutateComponentWithDelete extends MutateComponentCommonProps { +export interface MutateComponentWithDelete extends MutateComponentCommonProps { verb: "DELETE"; /** * A function that recieves a mutation function, along with @@ -55,10 +55,14 @@ export interface MutateComponentWithDelete extends MutateComponentCommonProps { * * @param actions - a key/value map of HTTP verbs, aliasing destroy to DELETE. */ - children: (mutate: (resourceId?: string | {}) => Promise, states: States, meta: Meta) => React.ReactNode; + children: ( + mutate: (resourceId?: string | {}) => Promise, + states: States, + meta: Meta, + ) => React.ReactNode; } -export interface MutateComponentWithOtherVerb extends MutateComponentCommonProps { +export interface MutateComponentWithOtherVerb extends MutateComponentCommonProps { verb: "POST" | "PUT" | "PATCH"; /** * A function that recieves a mutation function, along with @@ -66,19 +70,25 @@ export interface MutateComponentWithOtherVerb extends MutateComponentCommonProps * * @param actions - a key/value map of HTTP verbs, aliasing destroy to DELETE. */ - children: (mutate: (body?: string | {}) => Promise, states: States, meta: Meta) => React.ReactNode; + children: ( + mutate: (body?: string | {}) => Promise, + states: States, + meta: Meta, + ) => React.ReactNode; } -export type MutateComponentProps = MutateComponentWithDelete | MutateComponentWithOtherVerb; +export type MutateComponentProps = + | MutateComponentWithDelete + | MutateComponentWithOtherVerb; /** * State for the component. These * are implementation details and should be * hidden from any consumers. */ -export interface MutateComponentState { +export interface MutateComponentState { response: Response | null; - error: GetComponentState["error"]; + error: GetComponentState["error"]; loading: boolean; } @@ -87,8 +97,11 @@ export interface MutateComponentState { * is a named class because it is useful in * debugging. */ -class ContextlessMutate extends React.Component { - public readonly state: Readonly = { +class ContextlessMutate extends React.Component< + MutateComponentProps, + MutateComponentState +> { + public readonly state: Readonly> = { response: null, loading: false, error: null, @@ -146,12 +159,12 @@ class ContextlessMutate extends React.Component(props: MutateComponentProps) { return ( {contextProps => ( - + {...contextProps} {...props} /> )} diff --git a/src/Poll.tsx b/src/Poll.tsx index c2a57303..f2474921 100644 --- a/src/Poll.tsx +++ b/src/Poll.tsx @@ -17,23 +17,23 @@ interface Meta extends GetComponentMeta { /** * States of the current poll */ -interface States { +interface States { /** * Is the component currently polling? */ - polling: PollState["polling"]; + polling: PollState["polling"]; /** * Is the initial request loading? */ - loading: PollState["loading"]; + loading: PollState["loading"]; /** * Has the poll concluded? */ - finished: PollState["finished"]; + finished: PollState["finished"]; /** * Is there an error? What is it? */ - error: PollState["error"]; + error: PollState["error"]; } /** @@ -48,17 +48,17 @@ interface Actions { /** * Props that can control the Poll component. */ -interface PollProps { +interface PollProps { /** * What path are we polling on? */ - path: GetComponentProps["path"]; + path: GetComponentProps["path"]; /** * A function that gets polled data, the current * states, meta information, and various actions * that can be executed at the poll-level. */ - children: (data: T | null, states: States, actions: Actions, meta: Meta) => React.ReactNode; + children: (data: TData | null, states: States, actions: Actions, meta: Meta) => React.ReactNode; /** * How long do we wait between repeating a request? * Value in milliseconds. @@ -80,24 +80,24 @@ interface PollProps { * @param data - The data returned from the poll. * @param response - The full response object. This could be useful in order to stop polling when !response.ok, for example. */ - until?: (data: T | null, response: Response | null) => boolean; + until?: (data: TData | null, response: Response | null) => boolean; /** * Are we going to wait to start the poll? * Use this with { start, stop } actions. */ - lazy?: GetComponentProps["lazy"]; + lazy?: GetComponentProps["lazy"]; /** * Should the data be transformed in any way? */ - resolve?: GetComponentProps["resolve"]; + resolve?: GetComponentProps["resolve"]; /** * We can request foreign URLs with this prop. */ - base?: GetComponentProps["base"]; + base?: GetComponentProps["base"]; /** * Any options to be passed to this request. */ - requestOptions?: GetComponentProps["requestOptions"]; + requestOptions?: GetComponentProps["requestOptions"]; } /** @@ -105,7 +105,7 @@ interface PollProps { * implementation details not necessarily exposed to * consumers. */ -interface PollState { +interface PollState { /** * Are we currently polling? */ @@ -121,15 +121,15 @@ interface PollState { /** * What data are we holding in here? */ - data: GetComponentState["data"]; + data: GetComponentState["data"]; /** * Are we loading? */ - loading: GetComponentState["loading"]; + loading: GetComponentState["loading"]; /** * Do we currently have an error? */ - error: GetComponentState["error"]; + error: GetComponentState["error"]; /** * Index of the last polled response. */ @@ -139,8 +139,11 @@ interface PollState { /** * The component without context. */ -class ContextlessPoll extends React.Component, Readonly>> { - public readonly state: Readonly> = { +class ContextlessPoll extends React.Component< + PollProps, + Readonly> +> { + public readonly state: Readonly> = { data: null, loading: !this.props.lazy, lastResponse: null, @@ -157,7 +160,7 @@ class ContextlessPoll extends React.Component, Readonly { + private isModified = (response: Response, nextData: TData) => { if (response.status === 304) { return false; } @@ -208,7 +211,7 @@ class ContextlessPoll extends React.Component, Readonly extends React.Component, Readonly = { + const states: States = { polling, loading, error, @@ -281,7 +284,7 @@ class ContextlessPoll extends React.Component, Readonly(props: PollProps) { +function Poll(props: PollProps) { // Compose Contexts to allow for URL nesting return (