1 | # use-immer
|
2 |
|
3 | A hook to use [immer](https://github.com/mweststrate/immer) as a React [hook](https://reactjs.org/docs/hooks-intro.html) to manipulate state.
|
4 |
|
5 | # Installation
|
6 |
|
7 | `npm install immer use-immer`
|
8 |
|
9 | # API
|
10 |
|
11 | ## useImmer
|
12 |
|
13 | `useImmer(initialState)` is very similar to [`useState`](https://reactjs.org/docs/hooks-state.html).
|
14 | The function returns a tuple, the first value of the tuple is the current state, the second is the updater function,
|
15 | which accepts an [immer producer function](https://immerjs.github.io/immer/produce) or a value as argument.
|
16 |
|
17 | ### Managing state with immer producer function
|
18 |
|
19 | When passing a function to the updater, the `draft` argument can be mutated freely, until the producer ends and the changes will be made immutable and become the next state.
|
20 |
|
21 | Example: https://codesandbox.io/s/l97yrzw8ol
|
22 |
|
23 | ```javascript
|
24 | import React from "react";
|
25 | import { useImmer } from "use-immer";
|
26 |
|
27 |
|
28 | function App() {
|
29 | const [person, updatePerson] = useImmer({
|
30 | name: "Michel",
|
31 | age: 33
|
32 | });
|
33 |
|
34 | function updateName(name) {
|
35 | updatePerson(draft => {
|
36 | draft.name = name;
|
37 | });
|
38 | }
|
39 |
|
40 | function becomeOlder() {
|
41 | updatePerson(draft => {
|
42 | draft.age++;
|
43 | });
|
44 | }
|
45 |
|
46 | return (
|
47 | <div className="App">
|
48 | <h1>
|
49 | Hello {person.name} ({person.age})
|
50 | </h1>
|
51 | <input
|
52 | onChange={e => {
|
53 | updateName(e.target.value);
|
54 | }}
|
55 | value={person.name}
|
56 | />
|
57 | <br />
|
58 | <button onClick={becomeOlder}>Older</button>
|
59 | </div>
|
60 | );
|
61 | }
|
62 | ```
|
63 |
|
64 | (obviously, immer is a little overkill for this example)
|
65 |
|
66 | ### Managing state as simple useState hook
|
67 | When passing a value to the updater instead of a function, `useImmer` hook behaves the same as useState hook and updates the state with that value.
|
68 |
|
69 | ```javascript
|
70 | import React from 'react';
|
71 | import { useImmer } from 'use-immer';
|
72 |
|
73 | function BirthDayCelebrator(){
|
74 | const [age, setAge] = useImmer(20);
|
75 |
|
76 | function birthDay(event){
|
77 | setAge(age + 1);
|
78 | alert(`Happy birthday #${age} Anon! hope you good`);
|
79 | }
|
80 |
|
81 | return(
|
82 | <div>
|
83 | <button onClick={birthDay}>It is my birthday</button>
|
84 | </div>
|
85 | );
|
86 | }
|
87 | ```
|
88 |
|
89 | Obviously if you have to deal with immutability it is better option passing a function to the updater instead of a direct value.
|
90 |
|
91 | ## useImmerReducer
|
92 |
|
93 | Immer powered reducer, based on [`useReducer` hook](https://reactjs.org/docs/hooks-reference.html#usereducer)
|
94 |
|
95 | Example: https://codesandbox.io/s/2zor1monvp
|
96 |
|
97 | ```javascript
|
98 | import React from "react";
|
99 | import { useImmerReducer } from "use-immer";
|
100 |
|
101 | const initialState = { count: 0 };
|
102 |
|
103 | function reducer(draft, action) {
|
104 | switch (action.type) {
|
105 | case "reset":
|
106 | return initialState;
|
107 | case "increment":
|
108 | return void draft.count++;
|
109 | case "decrement":
|
110 | return void draft.count--;
|
111 | }
|
112 | }
|
113 |
|
114 | function Counter() {
|
115 | const [state, dispatch] = useImmerReducer(reducer, initialState);
|
116 | return (
|
117 | <>
|
118 | Count: {state.count}
|
119 | <button onClick={() => dispatch({ type: "reset" })}>Reset</button>
|
120 | <button onClick={() => dispatch({ type: "increment" })}>+</button>
|
121 | <button onClick={() => dispatch({ type: "decrement" })}>-</button>
|
122 | </>
|
123 | );
|
124 | }
|
125 | ```
|