Docs
- Getting Started
- SME Uploader
- Companion
- List of Plugins
- Common Plugin Options
- Custom Stores
- Locale Packs
UI Elements
Sources
- Drag & Drop
- File Input
- Webcam
- Provider Plugins
- ⓒ Dropbox
- ⓒ Google Drive
- ⓒ OneDrive
- ⓒ Zoom
- ⓒ Import From URL
Destinations
File Processing
- Image Editor
- Robodog Introduction
- Robodog File Picker
- Robodog Form
- Robodog Upload
- Robodog Dashboard
- Transloadit
Miscellaneous
Contributing
Custom Stores
This section concerns storing the internal application state, if you work with React/Redux, for example. If none of this rings a bell, you can safely skip this section.
By default, SME Uploader stores its internal state in an object.
If your app uses a state management library such as Redux, it can be useful to have SME Uploader store its state there instead—that way, you could write custom uploader UI components in the same way as the other components in the application.
SME Uploader comes with two state management solutions (stores):
@sme-uploader/store-default
, a simple object-based store.@sme-uploader/store-redux
, a store that uses a key in a Redux store.
There are also some third-party stores:
- uppy-store-ngrx, keeping SME Uploader state in a key in an Ngrx store for use with Angular.
Using stores
To use a store, pass an instance to the store
option in the SME Uploader constructor:
const defaultStore = require('@sme-uploader/store-default'); const uploader = new SmeUploader({ store: defaultStore() }); |
DefaultStore
SME Uploader uses the DefaultStore
…by default! You do not need to do anything to use it.
It does not take any options.
ReduxStore
The ReduxStore
stores SME Uploader state on a key in an existing Redux store.
The ReduxStore
dispatches uploader/STATE_UPDATE
actions to update state.
When the state in Redux changes, it notifies SME Uploader.
This way, you get most of the benefits of Redux, including support for the Redux Devtools and time traveling!
To use the ReduxStore
, add its reducer to the uploader
key:
const ReduxStore = require('@sme-uploader/store-redux'); const reducer = combineReducers({ ...reducers, uploader: ReduxStore.reducer }); |
Then pass a Redux store instance to the SME Uploader constructor:
const { createStore } = require('redux'); const ReduxStore = require('@sme-uploader/store-redux'); const store = createStore(reducer) const uploader = new SmeUploader({ store: ReduxStore({ store: store // That's a lot of stores! }) }); |
opts.store
Pass a Redux store instance, from Redux.createStore
.
This instance should have the SME Uploader reducer mounted somewhere already.
opts.id
By default, the ReduxStore
assumes SME Uploader state is stored on a state.uploader[id]
key.id
is randomly generated by the store constructor, but can be specified by passing an id
option if it should be predictable.
ReduxStore({ store: store, id: 'avatarUpload' }); |
opts.selector
If you’d rather not store the SME Uploader state under the state.uploader
key at all, use the selector
option to the ReduxStore
constructor to tell it where to find state instead:
const uploader = new SmeUploader({ store: ReduxStore({ store: store, id: 'avatarUpload', selector: state => state.pages.profile.uploader.avatarUpload }) }); |
Note that when specifying a custom selector, you must also specify a custom store ID. The store id
tells the reducer in which property it should put SME Uploader’s state. The selector must then take the state from that property. In the example, we set the ID to avatarUpload
and take the state from the [reducer mount path].avatarUpload
.
If your app uses reselect
, its selectors work very well with this!
Implementing Stores
An SME Uploader store is an object with three methods.
getState()
- Return the current state object.setState(patch)
- Merge the objectpatch
into the current state.subscribe(listener)
- Calllistener
whenever the state changes.listener
is a function that should receive three parameters:(prevState, nextState, patch)
The
subscribe()
method should return a function that ‘unsubscribes’ (removes) thelistener
.
The default store implementation, for example, looks a bit like this:
const defaultStore = () => { let state = {}; const listeners = new Set(); return { getState: () => state, setState: (patch) => { const prevState = state; const nextState = Object.assign({}, prevState, patch); state = nextState listeners.forEach((listener) => { listener(prevState, nextState, patch); }) }, subscribe: (listener) => { listeners.add(listener); return () => listeners.remove(listener); } } } |
A pattern like this, where users can pass options via a function call if necessary, is recommended.
See the @sme-uploader/store-default package for more inspiration.