ReduxStore.js 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. const cuid = require('cuid')
  2. // Redux action name.
  3. const STATE_UPDATE = 'uppy/STATE_UPDATE'
  4. // Pluck Uppy state from the Redux store in the default location.
  5. const defaultSelector = (id) => (state) => state.uppy[id]
  6. /**
  7. * Redux store.
  8. *
  9. * @param {object} opts.store - The Redux store to use.
  10. * @param {string} opts.id - This store instance's ID. Defaults to a random string.
  11. * If you need to access Uppy state through Redux, eg. to render custom UI, set this to something constant.
  12. * @param {function} opts.selector - Function, `(state) => uppyState`, to pluck state from the Redux store.
  13. * Defaults to retrieving `state.uppy[opts.id]`. Override if you placed Uppy state elsewhere in the Redux store.
  14. */
  15. class ReduxStore {
  16. constructor (opts) {
  17. this._store = opts.store
  18. this._id = opts.id || cuid()
  19. this._selector = opts.selector || defaultSelector(this._id)
  20. // Initialise the `uppy[id]` state key.
  21. this.setState({})
  22. }
  23. setState (patch) {
  24. this._store.dispatch({
  25. type: STATE_UPDATE,
  26. id: this._id,
  27. payload: patch
  28. })
  29. }
  30. getState () {
  31. return this._selector(this._store.getState())
  32. }
  33. subscribe (cb) {
  34. let prevState = this.getState()
  35. return this._store.subscribe(() => {
  36. const nextState = this.getState()
  37. if (prevState !== nextState) {
  38. const patch = getPatch(prevState, nextState)
  39. cb(prevState, nextState, patch)
  40. prevState = nextState
  41. }
  42. })
  43. }
  44. }
  45. function getPatch (prev, next) {
  46. const nextKeys = Object.keys(next)
  47. const patch = {}
  48. nextKeys.forEach((k) => {
  49. if (prev[k] !== next[k]) patch[k] = next[k]
  50. })
  51. return patch
  52. }
  53. function reducer (state = {}, action) {
  54. if (action.type === STATE_UPDATE) {
  55. const newState = Object.assign({}, state[action.id], action.payload)
  56. return Object.assign({}, state, {
  57. [action.id]: newState
  58. })
  59. }
  60. return state
  61. }
  62. function middleware () {
  63. // Do nothing, at the moment.
  64. return () => (next) => (action) => {
  65. next(action)
  66. }
  67. }
  68. module.exports = function createReduxStore (opts) {
  69. return new ReduxStore(opts)
  70. }
  71. module.exports.STATE_UPDATE = STATE_UPDATE
  72. module.exports.reducer = reducer
  73. module.exports.middleware = middleware