|
1 |
| -# redux.nim |
2 |
| -Redux.nim is a predictable state container for Nim apps |
| 1 | +# Redux.nim |
| 2 | + |
| 3 | +Redux.nim is a predictable state container for Nim apps. Nim version of [Redux.js](http://redux.js.org/). |
| 4 | + |
| 5 | +## Examples |
| 6 | + |
| 7 | +To run the examples below: |
| 8 | + |
| 9 | +``` |
| 10 | + nimble install # For first time |
| 11 | +``` |
| 12 | + |
| 13 | +``` |
| 14 | + cd redux/examples/ |
| 15 | + nim c -r counter.nim |
| 16 | + nim c -r todos.nim |
| 17 | + nim c -r todosundoable.nim |
| 18 | +``` |
| 19 | + |
| 20 | +### Counter |
| 21 | + |
| 22 | +```nim |
| 23 | +type |
| 24 | + CounterState = ref object |
| 25 | + count: int |
| 26 | + IncrementAction = ref object of Action |
| 27 | + DecrementAction = ref object of Action |
| 28 | +
|
| 29 | +proc counter(state: CounterState, action: Action): CounterState = |
| 30 | + if state == nil: |
| 31 | + return CounterState(count: 0) |
| 32 | + if action of IncrementAction: |
| 33 | + result = CounterState(count: state.count + 1) |
| 34 | + elif action of DecrementAction: |
| 35 | + result = CounterState(count: state.count - 1) |
| 36 | + else: |
| 37 | + result = state |
| 38 | +
|
| 39 | +var store = newStore(counter) |
| 40 | +
|
| 41 | +store.dispatch(IncrementAction()) |
| 42 | +echo store.getState().count |
| 43 | +
|
| 44 | +store.dispatch(DecrementAction()) |
| 45 | +echo store.getState().count |
| 46 | +``` |
| 47 | + |
| 48 | +Output: |
| 49 | + |
| 50 | +``` |
| 51 | +1 |
| 52 | +0 |
| 53 | +``` |
| 54 | + |
| 55 | +### Todos with Undo/Redo |
| 56 | + |
| 57 | +```nim |
| 58 | +type |
| 59 | + Todo = object |
| 60 | + text: string |
| 61 | + completed: bool |
| 62 | +
|
| 63 | + VisibilityFilter = enum |
| 64 | + All, |
| 65 | + Done, |
| 66 | + Incomplete |
| 67 | +
|
| 68 | + TodosStateObj = object |
| 69 | + filter: VisibilityFilter |
| 70 | + todos: seq[Todo] |
| 71 | + TodosState = ref TodosStateObj |
| 72 | +
|
| 73 | + AddTodoAction = ref object of Action |
| 74 | + text: string |
| 75 | +
|
| 76 | + ToggleTodoAction = ref object of Action |
| 77 | + index: Natural |
| 78 | +
|
| 79 | + SetFilterAction = ref object of Action |
| 80 | + filter: VisibilityFilter |
| 81 | +
|
| 82 | +{.experimental.} |
| 83 | +
|
| 84 | +using |
| 85 | + state: TodosState |
| 86 | + action: Action |
| 87 | + filter: VisibilityFilter |
| 88 | + todo: Todo |
| 89 | +
|
| 90 | +proc `$`(filter): string = |
| 91 | + case filter |
| 92 | + of All: "All" |
| 93 | + of Done: "Done" |
| 94 | + of Incomplete: "Incomplete" |
| 95 | +
|
| 96 | +proc `$`(state: UndoableState[TodosState]): string = |
| 97 | + let state = state.getPresent() |
| 98 | + result = "Todos(" & $state.filter & "):\n" |
| 99 | + let todos = state.todos.filter(proc(todo): bool = |
| 100 | + state.filter == All or todo.completed and state.filter == Done or not todo.completed and state.filter == Incomplete |
| 101 | + ) |
| 102 | + if len(todos) == 0: |
| 103 | + result &= "/empty/\n" |
| 104 | + else: |
| 105 | + for todo in todos: |
| 106 | + result &= (if todo.completed: "[x] " else: "[ ] ") & todo.text & "\n" |
| 107 | +
|
| 108 | +proc todos(state, action): TodosState = |
| 109 | + if state == nil: |
| 110 | + return TodosState( |
| 111 | + filter: VisibilityFilter.All, |
| 112 | + todos: @[] |
| 113 | + ) |
| 114 | + new(result); result[] = state[] |
| 115 | + if action of SetFilterAction: |
| 116 | + result.filter = SetFilterAction(action).filter |
| 117 | + elif action of AddTodoAction: |
| 118 | + let todo = Todo(text: AddTodoAction(action).text) |
| 119 | + result.todos = todo & result.todos |
| 120 | + elif action of ToggleTodoAction: |
| 121 | + let index = ToggleTodoAction(action).index |
| 122 | + var todo = result.todos[index] |
| 123 | + todo.completed = not todo.completed |
| 124 | + result.todos[index] = todo |
| 125 | + else: |
| 126 | + result = state |
| 127 | +
|
| 128 | +var store = newStore(undoable(todos)) |
| 129 | +
|
| 130 | +store.subscribe(proc (state: UndoableState[TodosState]) = echo $state) |
| 131 | +
|
| 132 | +store.dispatch(AddTodoAction(text: "First point")) |
| 133 | +store.dispatch(UndoAction()) |
| 134 | +store.dispatch(RedoAction()) |
| 135 | +store.dispatch(AddTodoAction(text: "Next point")) |
| 136 | +store.dispatch(ToggleTodoAction(index: 1)) |
| 137 | +store.dispatch(SetFilterAction(filter: Done)) |
| 138 | +store.dispatch(SetFilterAction(filter: Incomplete)) |
| 139 | +store.dispatch(ToggleTodoAction(index: 0)) |
| 140 | +store.dispatch(UndoAction()) |
| 141 | +store.dispatch(UndoAction()) |
| 142 | +store.dispatch(UndoAction()) |
| 143 | +store.dispatch(UndoAction()) |
| 144 | +store.dispatch(UndoAction()) |
| 145 | +store.dispatch(UndoAction()) |
| 146 | +``` |
| 147 | + |
| 148 | +Output: |
| 149 | + |
| 150 | +``` |
| 151 | +Todos(All): |
| 152 | +[ ] First point |
| 153 | +
|
| 154 | +Todos(All): |
| 155 | +/empty/ |
| 156 | +
|
| 157 | +Todos(All): |
| 158 | +[ ] First point |
| 159 | +
|
| 160 | +Todos(All): |
| 161 | +[ ] Next point |
| 162 | +[ ] First point |
| 163 | +
|
| 164 | +Todos(All): |
| 165 | +[ ] Next point |
| 166 | +[x] First point |
| 167 | +
|
| 168 | +Todos(Done): |
| 169 | +[x] First point |
| 170 | +
|
| 171 | +Todos(Incomplete): |
| 172 | +[ ] Next point |
| 173 | +
|
| 174 | +Todos(Incomplete): |
| 175 | +/empty/ |
| 176 | +
|
| 177 | +Todos(Incomplete): |
| 178 | +[ ] Next point |
| 179 | +
|
| 180 | +Todos(Done): |
| 181 | +[x] First point |
| 182 | +
|
| 183 | +Todos(All): |
| 184 | +[ ] Next point |
| 185 | +[x] First point |
| 186 | +
|
| 187 | +Todos(All): |
| 188 | +[ ] Next point |
| 189 | +[ ] First point |
| 190 | +
|
| 191 | +Todos(All): |
| 192 | +[ ] First point |
| 193 | +
|
| 194 | +Todos(All): |
| 195 | +/empty/ |
| 196 | +``` |
| 197 | + |
| 198 | +## TODO |
| 199 | + |
| 200 | +* Add `combineReducers`. |
| 201 | +* Elaborate on asyncrounus dispatch. |
| 202 | + |
| 203 | +## License |
| 204 | + |
| 205 | +This library is licensed under the MIT license. Read [LICENSE](https://github.com/pragmagic/redux.nim/blob/master/LICENSE) file for details. |
| 206 | + |
| 207 | +Copyright (c) 2017 Pragmagic, Inc. |
0 commit comments