How to tie emitted events events into redux-saga?

后端 未结 5 662
情书的邮戳
情书的邮戳 2020-12-28 18:45

I\'m trying to use redux-saga to connect events from PouchDB to my React.js application, but I\'m struggling to figure out how to connect events emitted from PouchDB to my S

5条回答
  •  情深已故
    2020-12-28 18:53

    As Nirrek explained it, when you need to connect to push data sources, you'll have to build an event iterator for that source.

    I'd like to add that the above mechanism could be made reusable. So we don't have to recreate an event iterator for each different source.

    The solution is to create a generic channel with put and take methods. You can call the take method from inside the Generator and connect the put method to the listener interface of your data source.

    Here is a possible implementation. Note that the channel buffers messages if no one is waiting for them (e.g. the Generator is busy doing some remote call)

    function createChannel () {
      const messageQueue = []
      const resolveQueue = []
    
      function put (msg) {
        // anyone waiting for a message ?
        if (resolveQueue.length) {
          // deliver the message to the oldest one waiting (First In First Out)
          const nextResolve = resolveQueue.shift()
          nextResolve(msg)
        } else {
          // no one is waiting ? queue the event
          messageQueue.push(msg)
        }
      }
    
      // returns a Promise resolved with the next message
      function take () {
        // do we have queued messages ?
        if (messageQueue.length) {
          // deliver the oldest queued message
          return Promise.resolve(messageQueue.shift())
        } else {
          // no queued messages ? queue the taker until a message arrives
          return new Promise((resolve) => resolveQueue.push(resolve))
        }
      }
    
      return {
        take,
        put
      }
    }
    

    Then the above channel can be used anytime you want to listen to an external push data source. For your example

    function createChangeChannel (replication) {
      const channel = createChannel()
    
      // every change event will call put on the channel
      replication.on('change', channel.put)
      return channel
    }
    
    function * startReplication (getState) {
      // Wait for the configuration to be set. This can happen multiple
      // times during the life cycle, for example when the user wants to
      // switch database/workspace.
      while (yield take(DATABASE_SET_CONFIGURATION)) {
        let state = getState()
        let wrapper = state.database.wrapper
    
        // Wait for a connection to work.
        yield apply(wrapper, wrapper.connect)
    
        // Trigger replication, and keep the promise.
        let replication = wrapper.replicate()
    
        if (replication) {
          yield call(monitorChangeEvents, createChangeChannel(replication))
        }
      }
    }
    
    function * monitorChangeEvents (channel) {
      while (true) {
        const info = yield call(channel.take) // Blocks until the promise resolves
        yield put(databaseActions.replicationChange(info))
      }
    }
    

提交回复
热议问题