UNPKG

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