Redux bindings for plupload
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
es6
test
.babelrc
.eslintignore
.eslintrc
.gitignore
.nvmrc
.travis.yml
LICENSE
README.md
package.json

README.md

Redux-plupload

FSA-compliant Redux bindings for Plupload.

GitHub license

Overview

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);
}

Usage

Getting started

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 INITed 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.

Calling plupload methods

Here is a list of plupload methods and the actions you can dispatch to call that method on the uploader instance:

init

dispatch ({ type: ActionTypes.INIT, payload: options });

setOption

dispatch ({ type: ActionTypes.SET_OPTION, payload: { option, value } });

refresh

dispatch ({ type: ActionTypes.REFRESH });

start

dispatch ({ type: ActionTypes.START });

stop

dispatch ({ type: ActionTypes.STOP });

disableBrowse

dispatch ({ type: ActionTypes.DISABLE_BROWSE, payload: { disable } });

addFile

dispatch ({ type: ActionTypes.ADD_FILE, payload: { file, fileName } });

removeFile

dispatch ({ type: ActionTypes.REMOVE_FILE, payload: { file } });

destroy

dispatch ({ type: ActionTypes.DESTROY });

splice

dispatch ({ type: ActionTypes.CLEAR });

Listening for plupload events

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.)

Init

if (action.type === ActionTypes.INITING) {
  const { uploader } = action.meta;
}

PostInit

if (action.type === ActionTypes.POST_INIT) {
   //
}

OptionChanged

if (action.type === ActionTypes.OPTION_CHANGED) {
   const { name, value, oldValue } = action.payload;
}

Refresh

if (action.type === ActionTypes.REFRESHING) {
   //
}

StateChanged

if (action.type === ActionTypes.STATE_CHANGED) {
   //
}

UploadFile

if (action.type === ActionTypes.UPLOAD_FILE) {
   const { file } = action.payload;
}

BeforeUpload

if (action.type === ActionTypes.BEFORE_UPLOAD) {
   const { file } = action.payload;
}

QueueChanged

if (action.type === ActionTypes.QUEUE_CHANGED) {
   //
}

UploadProgress

if (action.type === ActionTypes.UPLOAD_PROGRESS) {
   const { file } = action.payload;
}

FilesRemoved

if (action.type === ActionTypes.FILES_REMOVED) {
   const { files } = action.payload;
}

FileFiltered

if (action.type === ActionTypes.FILE_FILTERED) {
   const { file } = action.payload;
}

FilesAdded

if (action.type === ActionTypes.FILES_ADDED) {
   const { files } = action.payload;
}

FileUploaded

if (action.type === ActionTypes.FILE_UPLOADED) {
   const { file } = action.payload;
   const { response } = action.meta;
}

ChunkUploaded

if (action.type === ActionTypes.CHUNK_UPLOADED) {
  const { file } = action.payload;
  const { response } = action.meta;
}

UploadComplete

if (action.type === ActionTypes.UPLOAD_COMPLETE) {
  const { files } = action.payload;
}

Error

if (action.type === ActionTypes.ERROR) {
  const { error } = action.payload;
  console.log(action.error); // this flag will be set to true
}

Destroy

if (action.type === ActionTypes.DESTROYING) {
  //
}

Multiple uploaders

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');