Use Promises For Web-Worker With Redux

My setup is: Webpack, React, Redux (incl. redux-thunk).

I am working towards integrating web workers in my mouseMove eventListener. The need is to find out which elements have a collision with the ‘group selection’ rect as the user draws in the drawing app.

The call to web-worker is going to be async so, within the action-creator function, I am trying to raise a promise, which upon resolve, calls the payload creating func (resolve) as follows:

ACTION CREATOR:

export const groupSelectionPayload = ( a, b, c ) => {
    let something = doSomething( a, b );
    return( new Promise( function( resolve, reject ){
        let selectedElements = getSelectedElements( something, c );
        // Im not sure about the below condition,
        //  which I am using to call either resolve / reject funcs,
        //  is there a better way to handle this?
        if( selectedElements !== undefined ){
            resolve( something );
        } else {
            reject();
        }
    }));
};

// when promise resolves, we return the action to dispatch
const resolve = function( rectCoOrd ){
    return ({
        type : CREATE_GROUP_SELECTION_RECT,
        svgPayload : {
            curToolbarCtrlSelection : {
                ctrlName : "grpSelect",
                props : {
                    pos : {
                        x : rectCoOrd[ 0 ],
                        y : rectCoOrd[ 1 ],
                        w : rectCoOrd[ 2 ],
                        h : rectCoOrd[ 3 ]
                    }
                }
            }
        }
    });
};

// func posts message to web-worker
const getSelectedElements = ( something, c ) => {
    worker_handler.postMessage( iMap({
        type : "grpSelect",
    }));
};

I am using Redux-thunk for async, yet, I get the error:
Error: Actions must be plain objects. Use custom middleware for async actions. Followed by:
uncaught exception : undefined

What am I doing wrong and is there a more sensible way to go about handling the scenario discussed above?

Edit:
I needed to install redux-promise middleware which I have.

const store = createStore( reducer, composeEnhancer( applyMiddleware( thunk, promiseMiddleware )));

… which has resolved the Actions must be plain objects ... error. However, I am still getting the uncaught exception : undefined error.

Comments 1

  • Well I guess your action creator should look like so:

    export const groupSelectionPayload = ( a, b, c ) => dispatch => {
      //do some async stuff like so:
    
      new Promise((res, rej) => { … })
        .then(data => dispatch({type: 'success', payload: { data }}))
        .catch(error => dispatch({type: 'error', payload: { error }}))
    }
    

    Redux thunk will call the method returned from the creator with dispatch as parameter. So within that method you can dispatch other actions, when the async stuff is done, or before, or on progress.

    Additionally redux thunk will return the value of the function supplied by the action creator. So can also:

    const someAction = id => dispatch => new Promise((res, rej) => {
      const result = something(id);
      if (result !== null) {
        dispatch({type: 'success', payload: { result }})
        res(result);
      } else { … }
    
    });
    

    And in the component you than:

    this.props.action(<id>).then(/*getting fancy here, update State or something*/);
    

    But when you are dealing with a webWorker, I think middleware would be a better place to put the code:

    const customMiddleware = store => {
      //create and connect to the worker here
      const worker = …
      worker.onmessage = msg => store.dispatch({type: 'workermsg', payload: {msg}});
      return next => action => {
        if(action.type !== 'posttoworker') return next(action)
        worker.postMessage(action.payload.msg)
      }
    }
    

    I have not taken care too much about the worker code, its just about the idea, to use middle as api for the worker…

发表评论

电子邮件地址不会被公开。 必填项已用*标注