|
1 | 1 | # FAQ |
2 | 2 |
|
3 | | -Work-in-progress - check back later :) |
| 3 | +### Table of Contents |
| 4 | + |
| 5 | +- [Where can I get help using `redux-undo`?](#where-can-I-get-help-using-redux-undo) |
| 6 | +- [Where can I find examples of how to use `redux-undo`?](#where-can-i-find-examples-of-how-to-use-redux-undo) |
| 7 | +- [How do I prevent cluttering up history with rapidly changing state?](#how-do-I-prevent-cluttering-up-history-with-rapidly-changing-state) |
| 8 | +- [Can I have multiple, separate undoable functions?](#can-i-have-multiple-separate-undoable-functions) |
| 9 | +- [Why are my actions not being filtered?](#why-are-my-actions-not-being-filtered) |
| 10 | +- [What is `_latestUnfiltered`? Can I remove it?](#what-is-_latestUnfiltered-can-i-remove-it) |
| 11 | +- [Why am I getting `Cannot find module 'redux-undo'`?](#why-am-i-getting-cannot-find-module-redux-undo) |
| 12 | +- [How do I set an initial state/history?](upgrading-to-1.0.md#initialstate) |
| 13 | +- [How do I upgrade from 0.X to 1.0?](upgrading-to-1.0.md) |
| 14 | + |
| 15 | +## Where can I get help using `redux-undo`? |
| 16 | + |
| 17 | +To get an understanding of the basics, read through the [README](/README.md) and checkout some [examples](#where-can-i-find-examples-of-how-to-use-redux-undo). |
| 18 | + |
| 19 | +To get help with a specific use case, see if there is already an example in these docs or the examples. If not, ask for help in the [gitter chat](https://gitter.im/omnidan/redux-undo)! |
| 20 | + |
| 21 | +If it seems you have found a bug or you are itching for a new feature, go ahead and submit it as an issue following the template provided. Please reserve Github issues for bugs and features **only**. Ask any other questions on the gitter chat and someone will probably be able to help you with your problem. |
| 22 | + |
| 23 | +## Where can I find examples of how to use `redux-undo`? |
| 24 | + |
| 25 | +Look at the `examples/` directory of the project folder. The `todos-with-undo/` is a good project to start messing with. |
| 26 | + |
| 27 | +```sh |
| 28 | +$ git clone https://github.com/omnidan/redux-undo.git |
| 29 | +$ cd redux-undo/examples/todos-with-undo |
| 30 | +$ npm install |
| 31 | +$ npm start |
| 32 | +``` |
| 33 | + |
| 34 | +Just open http://localhost:3000 and you are good to go! |
| 35 | + |
| 36 | +## How do I prevent cluttering up history with rapidly changing state? |
| 37 | + |
| 38 | +The `throttled-drag/` project found the `examples/` directory gives a good demonstration of how to debounce undos (the filter is in `util/undoFilter.js`). |
| 39 | + |
| 40 | +This general question has different solutions depending on your exact problem. Let's say you have one or more rapidly dispatched actions, for example `MOVE_CURSOR` and `UPDATE_OBJECT_POS`, that ends with a lone action `PLACE_OBJECT`, and you only want to record the end state after `PLACE_OBJECT`. Then you can simply use a filter `excludeAction(['MOVE_CURSOR', 'UPDATE_OBJECT_POS'])` |
| 41 | + |
| 42 | +For more complex requirements, consider writing your own [custom filter](https://github.com/omnidan/redux-undo#custom-filters). |
| 43 | + |
| 44 | +## Can I have multiple, separate undoable functions? |
| 45 | + |
| 46 | +Yes you can! Simply wrap each reducer with its own `undoable()`. |
| 47 | + |
| 48 | +```js |
| 49 | +const rootReducer = combineReducers({ |
| 50 | + someData: undoable(dataReducer), |
| 51 | + otherData: undoable(otherDataReducer) |
| 52 | +}); |
| 53 | +``` |
| 54 | + |
| 55 | +Do not forget to setup different undo/redo types to undo/redo each slice separately. |
| 56 | + |
| 57 | +```js |
| 58 | +someData: undoable(dataReducer, { |
| 59 | + undoType: "DATA_UNDO", |
| 60 | + redoType: "DATA_REDO" |
| 61 | + // There is also jumpType, jumpToPastType, jumpToFutureType, clearHistoryType, and initTypes (which is an array of action types) |
| 62 | +}); |
| 63 | +``` |
| 64 | + |
| 65 | +If you wish to have a single conglomerate history that a user can undo one action at a time, you can wrap the root reducer with `undoable()`. |
| 66 | + |
| 67 | +```js |
| 68 | +const rootReducer = undoable( |
| 69 | + combineReducers({ |
| 70 | + someData: dataReducer, |
| 71 | + otherData: otherDataReducer |
| 72 | + }), |
| 73 | + {...options...} |
| 74 | +); |
| 75 | +``` |
| 76 | + |
| 77 | +You probably need to use [custom filters](https://github.com/omnidan/redux-undo#custom-filters) and/or [`groupBy`](https://github.com/omnidan/redux-undo#grouping-actions) to undo/redo in reasonable chunks. |
| 78 | + |
| 79 | +## Why are my actions not being filtered? |
| 80 | + |
| 81 | +If you are trying to prevent actions from changing state, **that is not what `filter` is for**. The `filter` option only prevents state changes from becoming part of the history, i.e. the new state being pushed into `state.past`. If you need this functionality, check out [redux-ignore](https://github.com/omnidan/redux-ignore). |
| 82 | + |
| 83 | +On the other hand, here is how to use the helper functions: |
| 84 | + |
| 85 | +```js |
| 86 | +undoable(myReducer, { |
| 87 | + filter: combineFilters( |
| 88 | + // includeAction/excludeAction helpers take an array of action type strings |
| 89 | + includeAction(["MY_ACTION", "ANOTHER_ACTION"]), |
| 90 | + costumeFilter |
| 91 | + ) |
| 92 | +}); |
| 93 | +``` |
| 94 | + |
| 95 | +When writing a custom filter, return `true` for actions that you want to keep in history. |
| 96 | + |
| 97 | +```js |
| 98 | +function onlyEveryThird(action, newState, history) { |
| 99 | + // Access the whole history object |
| 100 | + let { past, present, future, limit } = history; |
| 101 | + |
| 102 | + return newState.count % 3 === 0; // Only update history every third count |
| 103 | +} |
| 104 | +``` |
| 105 | + |
| 106 | +## What is `_latestUnfiltered`? Can I remove it? |
| 107 | + |
| 108 | +### What is it? |
| 109 | + |
| 110 | +State wrapped by `undoable()` contains the field `_latestUnfiltered` alongside `past`, `present`, etc. This field is used to keep track of state that should be put in the history but cannot yet because the previous action(s) were filtered. It is basically a temporary variable between filtered actions. |
| 111 | + |
| 112 | +```js |
| 113 | +// This action is filtered, so present cannot be pushed into past right away |
| 114 | +_latestUnfiltered = present; |
| 115 | +present = newState; |
| 116 | + |
| 117 | +// With the next unfiltered action... |
| 118 | +past = [...past, _latestUnfiltered]; // Now we can add it |
| 119 | +``` |
| 120 | + |
| 121 | +### Can I remove it? |
| 122 | + |
| 123 | +Short answer, no. It is an integral part of filtering actions from history and cannot be removed from the library. You can ignore it completely, but overriding/removing it may have unwanted consequences. |
| 124 | + |
| 125 | +While there is a tad more overhead handling actions in the reducer, it is necessary with the current setup. In the future, there might be optimization that makes this field less burdensome for users that do not use the filtering functionality. |
| 126 | + |
| 127 | +## Why am I getting `Cannot find module 'redux-undo'`? |
| 128 | + |
| 129 | +If you are using redux-undo in a CommonJS or UMD environment, you need to add `.default` to your imports. |
| 130 | + |
| 131 | +```js |
| 132 | +// CJS |
| 133 | +var undoable = require("redux-undo").default; |
| 134 | + |
| 135 | +// UMD |
| 136 | +var undoable = window.ReduxUndo.default; |
| 137 | +``` |
| 138 | + |
| 139 | +ES6 imports should work without a hitch. |
| 140 | + |
| 141 | +```js |
| 142 | +import undoable from "redux-undo"; |
| 143 | +``` |
| 144 | + |
| 145 | +If this fixed your issue, you might also want to checkout how to [upgrade from 0.6 to 1.0](upgrading-to-1.0.md). |
0 commit comments