react-hook-use-cta: (use Call To Action)

A React hook for managing complex state with custom actions, history tracking, and type safety.

Features
  • Type-safe state management
  • Initial state management
  • Built-in state history tracking
  • Built-in action types
    • update: Update current state
    • replace: Replace entire current state
    • updateInitial: Update initial state
    • replaceInitial: Replace initial state
    • reset: Reset current state to initial state, or replace initial state and current state
  • Flexible and customizable actions for state management

Install

react-hook-use-cta

NPM

npm i react-hook-use-cta

Yarn

yarn add react-hook-use-cta

useCTA

import { useCTA, } from 'react-hook-use-cta';

useCTA Basic Example

Click to view useCTA basic example

Parameter: initial

Parameter: onInit

Optional callback:

where Initial is the initial state structure.

Has the following key features:

  • Runs once on component mount
  • Receives the initial state as a parameter
  • Can return a new state object to override initial values
  • Perfect for setting up derived state or initial data from props
  • This makes onInit particularly useful when you need to perform calculations or transformations on your initial state before your component starts using it.
onInit Example
Click to view useCTA onInit parameter example

Parameter: compare

Optional callback:

previousValue and nextValue are the previous and next values a state property.

extra.key is the key which is being compared.

extra.cmp gives you access to strictDeepEqual from fast-equals

It should return:

  • true if the values are considered equal
  • false if the values are different

This is particularly useful when:

  • You need custom equality logic.
  • You want to optimize re-renders by comparing only specific properties.
  • Working with complex nested objects that need special comparison handling.
compare Example
Click to view useCTA compare parameter example

Parameter: actions

Optional Record with the following capabilities:

  • Gives you a clean, type-safe way to encapsulate your state logic while keeping your component code focused on presentation.
  • Defines reusable state operations
  • Maintains full TypeScript type safety
  • Can be called via dispatch.cta or dispatch
  • Can override the built-in actions
  • Can accept multiple parameters
  • Has access all built-in actions.

Overridable actions

All built-in call-to-actions (CTA) can have their behaviors extended or modified.

This pattern enables:

  • Adding custom validation
  • Transforming data
  • Adding side effects
  • Adding logging

Overridable actions Example

Click to view useCTA overridable actions parameter example

Overridable actions Parameter: CTAHistory

Gives you access to the complete read-only state object containing:

  • current: The current hook state
  • previous: The previous current state object before the last update.

    Starts of as null until current state is updated.

  • changes: The changes between the initial state and the current state.

    Is null if the there are no differences between the initial and current state.

  • initial: The initial state of the hook. Can be updated to reflect a point of synchronization.
  • previousInitial: The previous initial state object before the last update.

    Starts of as null until initial state is updated.

Overridable actions Parameter: payload

The second parameter is the expected signature of the overridden action (please refer to DefaultActionsRecord type).

  • replace: CTAState
  • replaceInitial: CTAState
  • reset: CTAState or undefined

    Note: sending undefined will reset the hook state to it's initial state.

  • update: Partial<CTAState>
  • updateInitial: Partial<CTAState>

Overridable actions return value

The expected return signature of the overridden action (please refer to DefaultActionsRecord type).

If the action returns undefined, the action will not be triggered.

  • replace: CTAState or undefined
  • replaceInitial: CTAState or undefined
  • reset: CTAState or undefined
  • update: Partial<CTAState> or undefined
  • updateInitial: Partial<CTAState> or undefined

Custom actions

Custom actions are a powerful way to extend the functionality of your state management system. This gives you the flexibility to:

  • Create domain-specific actions
  • Encapsulate complex state updates
  • Build reusable action patterns
  • Handle specialized business logic

They are defined as a record of functions, where the key is the action name and the value is the function that accepts any number of parameters.

Parameters are optional.

Custom actions Example

Click to view useCTA custom actions example

Custom action Parameter: CustomCTAHistory

The first parameter of the function is read-only CustomCTAHistory which extends from CTAHistory

and gives you access to all the built-in action behaviors.

By default, custom actions behave as an update, but you can customize them to behave like any other

built-in action through CustomCTAHistory.

Custom action Parameters: ...args

Custom actions can have any number of args after the CustomCTAHistory parameter.

These args can be of any type you can specify to ensure type safety,

and they will be passed to the action function when it is called.

Custom action return value

Custom actions can return several different types of values, depending on action type you want it to behave like.

  • undefined: Action will not be triggered. Return when you want to conditionally trigger an action.
  • Partial<CTAState>: This will have it behave like an update action. It will use using overridden update.
  • CustomCTAHistory.updateAction( Partial<CTAState>, { useDefault?: boolean } | undefined, )

    : This will have it behave like an update action.

    { useDefault: true } will bypass the overridden action behavior

  • CustomCTAHistory.replaceAction( CTAState, { useDefault?: boolean } | undefined, )

    : This will have it behave like an replace action.

    { useDefault: true } will bypass the overridden action behavior

  • CustomCTAHistory.resetAction( CTAState | undefined, { useDefault?: boolean } | undefined, )

    : Behaves like an reset action.

    { useDefault: true } will bypass the overridden action behavior

  • CustomCTAHistory.updateInitialAction( Partial<CTAState> | undefined, { useDefault?: boolean } | undefined, )

    : Behaves like an updateInitial action.

    { useDefault: true } will bypass the overridden action behavior

  • CustomCTAHistory.replaceInitialAction( CTAState | undefined, { useDefault?: boolean } | undefined, )

    : Behaves like an replaceInitial action.

    { useDefault: true } will bypass the overridden action behavior

Note: If you have overridden the built-in actions, the custom action will use the overridden action.

Sending { useDefault: true } will bypass the overridden action and behave using default action.

useCTA return values

useCTA returns a type-safe array with two elements for managing complex state operations while maintaining access to state history and change tracking.

useCTA return value [0]: history

useCTA return value [1]: dispatch

Gives you access to the dispatch function which allows you to trigger state history changes through actions.

Re-render will not occur if the state does not change or if the callback returns undefined.

The following built-in actions are available:

dispatch.cta.update


dispatch.cta.update( keyof CTAState, CTAState[keyof CTAState] );

dispatch.cta.update( Partial<CTAState> );

dispatch.cta.update( ( ctaHistory: CTAHistory<CTAState> ) => Partial<CTAState> | undefined );
		
Alternate dispatch.cta.update

dispatch( {
	type: 'update',
	payload: Partial<CTAState>
} );

dispatch( {
	type: 'update',
	payload: ( ctaHistory: CTAHistory<CTAState> ) => Partial<CTAState> | undefined
} );
				

Lets you modify specific properties of your current state while preserving other values.

dispatch.cta.replace


dispatch.cta.replace( CTAState );

dispatch.cta.replace( ( ctaHistory: CTAHistory<CTAState> ) => CTAState | undefined );
		
Alternate dispatch.cta.replace

dispatch( {
	type: 'replace',
	payload: CTAState
} );

dispatch( {
	type: 'replace',
	payload: ( ctaHistory: CTAHistory<CTAState> ) => CTAState | undefined
} );
				

Replaces all current property values with new property values.

dispatch.cta.reset


// Reset the state to the initial state
dispatch.cta.reset();

// sets the current state and initial state to payload
dispatch.cta.reset( CTAState );

// sets the current state and initial state to what is returned from the callback
// if the callback returns undefined, the state will not change
dispatch.cta.reset( ( ctaHistory: CTAHistory<CTAState> ) => CTAState | undefined );
		
Alternate dispatch.cta.reset

// Reset the state to the initial state
dispatch( {
	type: 'reset',
} );

// sets the current state and initial state to payload
dispatch( {
	type: 'reset',
	payload: CTAState
} );

// sets the current state and initial state to what is returned from the callback
// if the callback returns undefined, the state will not change
dispatch( {
	type: 'reset',
	payload: ( ctaHistory: CTAHistory<CTAState> ) => CTAState | undefined
} );
				

Resets the current state back to the initial state or to synchronize the current state and the initial state.

dispatch.cta.updateInitial


dispatch.cta.updateInitial( Partial<CTAState> );

dispatch.cta.updateInitial( ( ctaHistory: CTAHistory<CTAState> ) => Partial<CTAState> | undefined );
		
Alternate dispatch.cta.updateInitial

dispatch( {
	type: 'updateInitial',
	payload: Partial<CTAState>
} );

dispatch( {
	type: 'updateInitial',
	payload: ( ctaHistory: CTAHistory<CTAState> ) => Partial<CTAState> | undefined
} );
				

Lets you modify specific properties of your initial state while preserving other values.

dispatch.cta.replaceInitial


dispatch.cta.replaceInitial( CTAState );

dispatch.cta.replaceInitial( ( ctaHistory: CTAHistory<CTAState> ) => CTAState | undefined );
				
Alternate dispatch.cta.replaceInitial

dispatch( {
	type: 'replaceInitial',
	payload: CTAState
} );

dispatch( {
	type: 'replaceInitial',
	payload: ( ctaHistory: CTAHistory<CTAState> ) => CTAState | undefined
} );
						

Used to replace all initial state property values with new property values.

dispatch.cta.YourCustomAction


dispatch.cta.YourCustomActionWithoutArgs();

dispatch.cta.YourCustomActionWithArgs( 
	Payload,
	...any[] | undefined
 );

dispatch.cta.YourCustomActionWithArgs( 
	( ( ctaHistory: CTAHistory<CTAState> ) => Payload | undefined ),
	 ...any[] | undefined 
);
	
Alternate dispatch.cta.YourCustomAction

dispatch( {
	type: 'YourCustomActionWithoutArgs',
} );

dispatch( {
	type: 'YourCustomActionWithArgs',
	payload: Payload,
	args: any[] | undefined,
} );

dispatch( {
	type: 'YourCustomActionWithArgs',
	payload: ( ctaHistory: CTAHistory<CTAState> ) => Payload | undefined
	args: any[] | undefined,
} );
				

YourCustomAction is a placeholder for the name of a custom action you defined in Custom actions

dispatch.history