1.0.3 • Published 2 years ago
@react-things/use-reducer-actions v1.0.3
useReducerActions
useReducer with actions
Install
npm install @react-things/use-reducer-actions
yarn add @react-things/use-reducer-actions
Usage
import { useReducerActions } from '@react-things/use-reducer-actions';
const Counter = () => {
const [
count,
{ increment, decrement, incrementByAmount },
] = useReducerActions({
initialState: 0,
reducers: {
increment: state => state + 1,
decrement: state => state - 1,
incrementByAmount: (state, amount: number) => state + amount,
},
});
return (
<div>
<div>
<button onClick={decrement}>-</button>
<div data-testid="count">{count}</div>
<button onClick={increment}>+</button>
</div>
<div>
<button onClick={() => incrementByAmount(3)}>Increment by 3</button>
</div>
</div>
);
};
import { useReducerActions } from '@react-things/use-reducer-actions';
type Todo = {
id: string;
text: string;
isDone: boolean;
};
const Todos = () => {
const [todos, { addTodo }] = useReducerActions({
initialState: [] as Todo[],
reducers: {
addTodo: (state, todo: Todo) => [...state, todo],
},
});
return (
<div>
<ul>
{todos.map(todo => {
return (
<li key={todo.id}>
{todo.text}
{todo.isDone && '✅'}
</li>
);
})}
</ul>
<button
onClick={() => {
addTodo({ id: '1', text: 'New todo', isDone: false });
}}
>
Add todo
</button>
</div>
);
};
ℹ️ The actions object you get back from
useReducerActions
is memoized (it never changes it's reference)
Examples
This library goes nicely with the library constate, which is a helper for creating context.
import { useReducerActions } from '@react-things/use-reducer-actions';
import constate from 'constate';
type Book {
id: string;
title: string;
author: string;
numberInStock: number;
}
const useBooks = () => {
const [books, bookActions] = useReducerActions({
initialState: [],
reducers: {
sellBook: (books, id: string) => books.map(book => {
if(book.id === id) return {...book, numberInStock: book.numberInStock - 1}
return book;
})
}
})
return [books, bookActions]
}
// actions are memoized, so useBookActions will never cause a render!
const [BookProvider, useBooksState, useBookActions] = constate(useBooks, v => v[0], v => v[1])
const App = () => {
return (
<BookProvider>
<Books />
</BookProvider>
)
}
const Books = () => {
const books = useBookState();
// ... render books
}