Let's compare these approaches with clear examples to showcase react-hook-use-cta's advantages:
- useState vs useCTA:
// useState
const [profile, setProfile] = useState({
user: {
id: '',
name: '',
email: '',
preferences: {
theme: 'light',
notifications: true
}
},
stats: {
lastLogin: null,
loginCount: 0,
activeProjects: []
}
});
const updatePreferences = (newPrefs) => {
setProfile(prev => ({
...prev,
user: {
...prev.user,
preferences: {
...prev.user.preferences,
...newPrefs
}
}
}));
};
const incrementLoginCount = () => {
setProfile(prev => ({
...prev,
stats: {
...prev.stats,
loginCount: prev.stats.loginCount + 1,
lastLogin: new Date()
}
}));
};
// useCTA - with history tracking and type safety
const [history, dispatch] = useCTA({
initial: {
user: {
id: '',
name: '',
email: '',
preferences: {
theme: 'light',
notifications: true
}
},
stats: {
lastLogin: null,
loginCount: 0,
activeProjects: []
}
},
actions: {
updatePreferences({current}, newPrefs) {
return {
user: {
...current.user,
preferences: {
...current.user.preferences,
...newPrefs
}
}
}
},
incrementLoginCount({current},) {
return {
stats: {
...current.stats,
loginCount: current.stats.loginCount + 1,
lastLogin: new Date()
}
}
}
}
});
- useReducer vs useCTA:
// useReducer
const reducer = (state, action) => {
switch (action.type) {
case 'update':
return { ...state, ...action.payload };
case 'reset':
return initialState;
case 'increment':
return { ...state, count: state.count + 1 };
default:
return state;
}
};
const [state, dispatch] = useReducer(reducer, { count: 0 });
// useCTA - built-in actions and type inference
const [history, dispatch] = useCTA({
initial: { count: 0 },
actions: {
increment(ctaHistory) {
const { current } = ctaHistory;
return { count: current.count + 1 };
}
}
});
// Built-in: dispatch.update(), dispatch.reset(), dispatch.replace()
- createContext vs createCTAContext:
// Regular Context
const CountContext = createContext(null);
const CountProvider = ({ children }) => {
const [count, setCount] = useState(0);
return (
<CountContext.Provider value={{ count, setCount }}>
{children}
</CountContext.Provider>
);
};
// createCTAContext - includes history and type-safe dispatch
const { CTAProvider, useCTAHistoryContext, useCTADispatchContext } = createCTAContext({
initial: { count: 0 },
actions: {
increment(ctaHistory) {
const { current } = ctaHistory;
return { count: current.count + 1 };
}
}
});
- Zustand vs createCTASelector
// Zustand approach
type ProfileState = {
user: {
id: string;
name: string;
email: string;
preferences: {
theme: 'light' | 'dark';
notifications: boolean;
};
};
stats: {
lastLogin: Date | null;
loginCount: number;
activeProjects: string[];
};
updatePreferences: (prefs: Partial<ProfileState['user']['preferences']>) => void;
incrementLoginCount: () => void;
addProject: (projectId: string) => void;
getNameEmail: () => Pick<ProfileState['user'], 'name' | 'email'>;
}
const useProfileStore = create<ProfileState>((set, get) => ({
user: {
id: '',
name: '',
email: '',
preferences: {
theme: 'light',
notifications: true
}
},
stats: {
lastLogin: null,
loginCount: 0,
activeProjects: []
},
getNameEmail: () =>({
name: get().user.name,
email: get().user.email
}),
updatePreferences: (prefs) => set((state) => ({
user: {
...state.user,
preferences: {
...state.user.preferences,
...prefs
}
}
})),
incrementLoginCount: () => set((state) => ({
stats: {
...state.stats,
loginCount: state.stats.loginCount + 1,
lastLogin: new Date()
}
})),
addProject: (projectId) => set((state) => ({
stats: {
...state.stats,
activeProjects: [...state.stats.activeProjects, projectId]
}
}))
}));
const nameEmail = useProfileStore(useShallow((state) => state.getNameEmail()));
// react-hook-use-cta approach with history tracking and type safety
const useProfileCTA = createCTASelector({
initial: {
user: {
id: '',
name: '',
email: '',
preferences: {
theme: 'light' as 'light' | 'dark',
notifications: true
}
},
stats: {
lastLogin: null as Date | null,
loginCount: 0,
activeProjects: [] as string[]
}
},
actions: {
updatePreferences({ current }, payload: Partial<typeof current.user.preferences>) {
return {
user: {
...current.user,
preferences: {
...current.user.preferences,
...payload
}
}
};
},
incrementLoginCount({ current }) {
return {
stats: {
...current.stats,
loginCount: current.stats.loginCount + 1,
lastLogin: new Date()
}
};
},
addProject({ current }, projectId: string) {
return {
stats: {
...current.stats,
activeProjects: [...current.stats.activeProjects, projectId]
}
};
}
},
createFunc(dispatch) {
return {
getNameEmail() {
const { current } = dispatch.history;
return {
name: current.user.name,
email: current.user.email,
};
}
}
}
});
const nameEmail = useProfileCTA(({dispatch}) => dispatch.func.getNameEmail());