Security News
The Unpaid Backbone of Open Source: Solo Maintainers Face Increasing Security Demands
Solo open source maintainers face burnout and security challenges, with 60% unpaid and 60% considering quitting.
use-dispatch-action
Advanced tools
Typed utilities for improving the experience with `useReducer`.
Typed utilities for improving the experience with useReducer
.
When using useReducer
use-dispatch-action
is a collection of utilities to improve the experience when using the useReducer
hook.
Install
yarn add use-dispatch-action
Or
npm install use-dispatch-action
import * as React from 'react';
import { useDispatchAction } from 'use-dispatch-action';
type Actions =
| { type: 'increment' }
| { type: 'decrement' }
| { type: 'addValue'; payload: number };
type State = { counter: number };
const reducer = (state: State, action: Actions): State => {
switch (action.type) {
case 'increment':
return { ...state, counter: state.counter + 1 };
case 'decrement':
return { ...state, counter: state.counter - 1 };
case 'addValue':
return { ...state, counter: state.counter + action.payload };
default:
return state;
}
};
const Component = () => {
const [state, dispatch] = React.useReducer(reducer, { counter: 0 });
const increment = useDispatchAction(dispatch, 'increment');
const decrement = useDispatchAction(dispatch, 'decrement');
const addValue = useDispatchAction(dispatch, 'addValue');
return (
<div>
<div title="counter">{state.counter}</div>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={() => addValue(2)}>Add Two</button>
</div>
);
};
Action
A utilty type for defining actions
type Action<TActionType extends string, TPayload = never> = {
type: TActionType;
payload?: TPayload;
};
type Actions = Action<'incrementOne'> | Action<'increment', number>;
useDispatchAction
Creates type safe dispatch functions for the specified action
useDispatchAction<TAction>(
dispatch: React.Dispatch<TAction>,
action: string
) : DispatchAction<TActionPayload>
dispatch: React.Dispatch<TAction>
- A dispatch method retured from React.useReducer
action: string
- The type of the actionDispatchAction<TActionPayload>
- Function to dispatch action// For actions without a payload
() => void;
// For actions with a payload
(payload: TPayload) => void;
const Component = () => {
const [state, dispatch] = React.useReducer(reducer, { counter: 0 });
const increment = useDispatchAction(dispatch, 'increment');
const decrement = useDispatchAction(dispatch, 'decrement');
const addValue = useDispatchAction(dispatch, 'addValue');
return (
<div>
<div title="counter">{state.counter}</div>
<button onClick={() => increment()}>Increment</button>
<button onClick={() => decrement()}>Decrement</button>
<button onClick={() => addValue(2)}>Add Two</button>
</div>
);
};
useDispatchReducer
Creates a reducer with a type safe dispatch method
useDispatchReducer<TState, TAction> (
reducer: React.Reducer<TState, TAction>,
initialState: TState
) : [state: TState, ActionDispatcher<TAction>]
TState
and TAction
can be infered by providing the type of a reducer.
useDispatchReducer<TReducer>(
reducer: TReducer,
initialState: TState
) : [state: TState, ActionDispatcher<TAction>]
reducer: React.Reducer<TState, TAction>
- The reducerinitialState: TState
- State to initialize the reducer with. A note, useDispatchReducer
does not implement lazy loading the stateA tuple with:
state: TState
- State of the reducerActionDispatcher<TAction>
- Function to dispatch actions in the form of tuples
// For actions without a payload
([type: string]) => void;
// For actions with a payload
([type: string, payload: TPayload]) => void;
With type inference
const Component = () => {
const [state, dispatch] = useDispatchReducer(reducer, { counter: 0 });
const increment = () => dispatch(['increment']);
const decrement = () => dispatch(['decrement']);
const addValue = (number: number) => dispatch(['addValue', number]);
return (
<div>
<div title="counter">{state.counter}</div>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={() => addValue(2)}>Add Two</button>
</div>
);
};
With known State and Action types
const Component = () => {
const [state, dispatch] = useDispatchReducer<State, Action>(reducer, {
counter: 0,
});
const increment = () => dispatch(['increment']);
const decrement = () => dispatch(['decrement']);
const addValue = (number: number) => dispatch(['addValue', number]);
return (
<div>
<div title="counter">{state.counter}</div>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={() => addValue(2)}>Add Two</button>
</div>
);
};
Only know the State type? The Action type can be inferred from the reducer as long as the actions are typed.
const Component = () => {
const [state, dispatch] = useDispatchReducer<State>(reducer, { counter: 0 });
const increment = () => dispatch(['increment']);
const decrement = () => dispatch(['decrement']);
const addValue = (number: number) => dispatch(['addValue', number]);
return (
<div>
<div title="counter">{state.counter}</div>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={() => addValue(2)}>Add Two</button>
</div>
);
};
A context based dispatcher used to prevent prop drilling
export type DispatchContextProps = {
initialState: TState;
reducer: React.Reducer<TState, TAction>;
};
initialState: TState
- state to initialize the reducer withreducer: React.Reducer<TState, TAction>
- The reducerUsing a consumer
const DispatchContext = () => {
return (
<DispatchContextProvider reducer={reducer} initialState={{ counter: 0 }}>
<DispatchContextConsumer>
{({ state, dispatch }: DispatchProps<typeof reducer>) => (
<div>
<div title="counter">{state.counter}</div>
<button onClick={() => dispatch(['increment'])}>Increment</button>
<button onClick={() => dispatch(['decrement'])}>Decrement</button>
<button onClick={() => dispatch(['addValue', 2])}>Add Two</button>
</div>
)}
</DispatchContextConsumer>
</DispatchContextProvider>
);
};
Using useDispatchContext
const Component = () => {
return (
<DispatchContextProvider initialState={{ counter: 0 }} reducer={reducer}>
<Counter />
</DispatchContextProvider>
);
};
const Counter = () => {
const [state, dispatch] = useDispatchContext<typeof reducer>();
return (
<div>
<div title="counter">{state.counter}</div>
<button onClick={() => dispatch(['increment'])}>Increment</button>
<button onClick={() => dispatch(['decrement'])}>Decrement</button>
<button onClick={() => dispatch(['addValue', 2])}>Add Two</button>
</div>
);
};
type Actions =
| { type: 'increment' }
| { type: 'decrement' }
| { type: 'addValue'; payload: number };
type State = { counter: number };
const reducer = (state: State, action: Actions): State => {
switch (action.type) {
case 'increment':
return { ...state, counter: state.counter + 1 };
case 'decrement':
return { ...state, counter: state.counter - 1 };
case 'addValue':
return { ...state, counter: state.counter + action.payload };
default:
return state;
}
};
1.0.0
FAQs
Typed utilities for improving the experience with `useReducer`.
The npm package use-dispatch-action receives a total of 1 weekly downloads. As such, use-dispatch-action popularity was classified as not popular.
We found that use-dispatch-action demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Solo open source maintainers face burnout and security challenges, with 60% unpaid and 60% considering quitting.
Security News
License exceptions modify the terms of open source licenses, impacting how software can be used, modified, and distributed. Developers should be aware of the legal implications of these exceptions.
Security News
A developer is accusing Tencent of violating the GPL by modifying a Python utility and changing its license to BSD, highlighting the importance of copyleft compliance.