FSA-compliant Redux bindings for Plupload.
redux-plupload
helps you use Redux actions for bi-directional communication with a plupload
uploader instance.
You can dispatch an action to call a plupload
method. For example, to start an upload:
// action.js
dispatch({ type: ActionTypes.START })
And redux-plupload
will dispatch an action so you know when a plupload
event occurs. For example, when plupload
reports on upload progress:
// reducer.js
if (action.type === ActionTypes.UPLOAD_PROGRESS) {
console.log('Uploading file', action.payload.name);
console.log('Percent complete', action.payload.percent);
}
To use redux-plupload
, you must install the middleware (and optionally the reducer), then send an ActionTypes.INIT
message to init the plupload.Uploader
. The payload
of the action should include a browse_button
(and optionaly dropzone
) prop. You can also specify url
and multipart_params
props at INIT
time, or provide an uploadSettingsSelector
that will be called with state
and file
as args to find the extra per-file upload settings.
// client.js
import ReactDOM from 'react-dom';
import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import { Provider } from 'react-redux';
import { reducer as uploaderReducer, createMiddleware as createUploaderMiddleware } from 'redux-plupload';
import UploadButton from './UploadButton';
const reducer = combineReducers({ uploader: uploaderReducer });
const uploadSettingsSelector = (state, file) => sate.path.to.server.upload.settings.for[file.id];
const uploaderMiddleware = createUploaderMiddleware(global.plupload, { uploadSettingsSelector });
const store = createStore(
reducer,
{},
applyMiddleware(uploaderMiddleware)
);
ReactDOM.render(
<Provider store={store}>
<UploadButton />
</Provider>,
global.document.getElementById('js-app')
);
// UploadButton.js
import { connect } from 'redux';
import { ActionTypes } from 'redux-plupload';
const uploaderInit(payload) => ({ type: ActionTypes.INIT, payload });
class UploadButton extends Component {
componentDidMount() {
this.props.initUploader({ browse_button: this._browseButton });
}
render() {
return (
<button
type="button"
ref={(browseButton) => (this._browseButton = browseButton)}
>Upload Files</button>
);
}
}
export default connect(
() => ({}),
(dispatch) => ({ initUploader: (payload) => dispatch(uploaderInit(payload)) })
)(UploadButton);
Once you've INIT
ed redux-plupload
, it will call the plupload.Uploader
's methods in response to actions, and emit actions based on the events that the plupload.Uploader
emits (with a few name-changes where they clash). If you install the reducer, it will keep its state up to date with a copy of the plupload.Uploader
state.
Here is a list of plupload
methods and the actions you can dispatch to call that method on the uploader instance:
dispatch ({ type: ActionTypes.INIT, payload: options });
dispatch ({ type: ActionTypes.SET_OPTION, payload: { option, value } });
dispatch ({ type: ActionTypes.REFRESH });
dispatch ({ type: ActionTypes.START });
dispatch ({ type: ActionTypes.STOP });
dispatch ({ type: ActionTypes.DISABLE_BROWSE, payload: { disable } });
dispatch ({ type: ActionTypes.ADD_FILE, payload: { file, fileName } });
dispatch ({ type: ActionTypes.REMOVE_FILE, payload: { file } });
dispatch ({ type: ActionTypes.DESTROY });
dispatch ({ type: ActionTypes.CLEAR });
The following actions will be dispatched when plupload
events occur.
Each action's meta
property will also contain the uploader
as shown in the first example below.
(If the {}
syntax is new to you, take a look at ES6 Object Destructuring.)
if (action.type === ActionTypes.INITING) {
const { uploader } = action.meta;
}
if (action.type === ActionTypes.POST_INIT) {
//
}
if (action.type === ActionTypes.OPTION_CHANGED) {
const { name, value, oldValue } = action.payload;
}
if (action.type === ActionTypes.REFRESHING) {
//
}
if (action.type === ActionTypes.STATE_CHANGED) {
//
}
if (action.type === ActionTypes.UPLOAD_FILE) {
const { file } = action.payload;
}
if (action.type === ActionTypes.BEFORE_UPLOAD) {
const { file } = action.payload;
}
if (action.type === ActionTypes.QUEUE_CHANGED) {
//
}
if (action.type === ActionTypes.UPLOAD_PROGRESS) {
const { file } = action.payload;
}
if (action.type === ActionTypes.FILES_REMOVED) {
const { files } = action.payload;
}
if (action.type === ActionTypes.FILE_FILTERED) {
const { file } = action.payload;
}
if (action.type === ActionTypes.FILES_ADDED) {
const { files } = action.payload;
}
if (action.type === ActionTypes.FILE_UPLOADED) {
const { file } = action.payload;
const { response } = action.meta;
}
if (action.type === ActionTypes.CHUNK_UPLOADED) {
const { file } = action.payload;
const { response } = action.meta;
}
if (action.type === ActionTypes.UPLOAD_COMPLETE) {
const { files } = action.payload;
}
if (action.type === ActionTypes.ERROR) {
const { error } = action.payload;
console.log(action.error); // this flag will be set to true
}
if (action.type === ActionTypes.DESTROYING) {
//
}
If you need to have more than one upload button or dropzone on a page, you can use redux-plupload
to manage multiple uploader instances. This can be done by specifying a unique handle
(a nickname) for each uploader on every interaction. If no handle
is specified, the interaction is assumed to be with the default uploader instance.
Initialising an uploader with a handle:
const options = {
handle: 'myUploader',
// other options
};
dispatch ({ type: ActionTypes.INIT, payload: options });
Calling methods on a specific uploader
dispatch ({ type: ActionTypes.START, meta: { handle: 'myUploader' } });
Listening for events from a specific uploader
if (action.type === ActionTypes.FILES_ADDED) {
const { files } = action.payload;
const { uploader } = action.meta;
console.log(uploader.handle); // 'myUploader'
}
Creating a reducer for a specific uploader
import { createReducer } from 'redux-plupload';
const myReducer = createReducer('myUploader');