react-ctx-toolkit
is a simple, compact, uncomplicated package inspired by @reduxjs/toolkit
that includes helper functions for better coding with Context API
With yarn
yarn add react-ctx-toolkit
With NPM
npm install react-ctx-toolkit
const increment = createAction<number | undefined>("INCREMENT")
const decrement = createAction<number | undefined>("DECREMENT")
type CounterState = {
count: number
}
const initialState: CounterState = {
count: 0,
}
const reducer = createReducer<CounterState>((builder) => {
builder
.addCase(increment, (state, action) => {
state.count += action.payload || 1
return state
})
.addCase(decrement, (state, action) => {
state.count -= action.payload || 1
return state
})
})
const {
Provider: CounterProvider,
hooks: [useCounter, useCounterDispatch],
} = createContext({ displayName: "Counter", initialState }, reducer)
function App() {
const count = useCounter((state) => state.count)
const dispatch = useCounterDispatch()
const handleIncrement = () => {
dispatch(increment(5))
}
const handleDecrement = () => {
dispatch(decrement(5))
}
return (
<>
<button onClick={handleIncrement}>Increment</button>
count: {count}
<button onClick={handleDecrement}>Decrement</button>
</>
)
}
function Root() {
return (
<CounterProvider>
<App />
</CounterProvider>
)
}
A helper function for defining an action.
const increment = createAction<number | undefined>("INCREMENT")
increment() // { type: "INCREMENT" }
increment(2) // { type: "INCREMENT", payload: 2 }
/* ----------------- */
const addUser = createAction("ADD_USER", (name: string, age: number) => ({
payload: { name, age },
}))
addUser("bob", "32")
// { type: "ADD_USER", payload: { name: "bob", age: "32" } }
/* ----------------- */
type User = {
name: string
age: number
}
const addUser = createAction<User>("ADD_USER")
addUser({ name: "bob", age: "32" })
// { type: "ADD_USER", payload: { name: "bob", age: "32" } }
A helper function for creating a reducer.
const increment = createAction<number | undefined>("INCREMENT")
const decrement = createAction<number | undefined>("DECREMENT")
type StateType = {
count: number
}
const reducer = createReducer<StateType>((builder) => {
builder
.addCase(increment, (state, action) => {
state.count += action.payload || 1
return state
})
.addCase(decrement, (state, action) => {
state.count -= action.payload || 1
return state
})
})
It is a helper function for creating context, provider, and hooks.
const {
Provider: CounterProvider,
contexts: [CounterContext, CounterDispatchContext],
hooks: [useCounter, useCounterDispatch],
} = createContext({ displayName: "Counter", initialState }, reducer)
In React Context when a context value is changed, all components that use useContext
will re-render. useSelector
helps you solve this issue and get better performance.
If you use hooks exported from
createContext
, you don't need to useuseSelector
. because the hooks useuseSelector
internally.
const theme = useSelector(AppContext, (state) => state.theme)