Skip to content
This repository has been archived by the owner on Mar 15, 2018. It is now read-only.

What about web sockets and alike? #25

Open
davidpfahler opened this issue May 27, 2015 · 5 comments
Open

What about web sockets and alike? #25

davidpfahler opened this issue May 27, 2015 · 5 comments
Assignees

Comments

@davidpfahler
Copy link

Transmit looks fantastic and I cannot wait to give it a try. However, what immediately came to my mind is how one would include something like web sockets or any other continuous message system? For example, consider a chat application: You might want to load a batch of most recent messages on load with one GET request (that could be done with Transmit), but you then want to get subsequent messages via web sockets. How would you do that (with Transmit)?

Thank you very much for all your effort you put into this project!

@RickWong RickWong self-assigned this Jun 1, 2015
@RickWong
Copy link
Owner

RickWong commented Jun 1, 2015

I've been wanting to add support for Streams and maybe Observables. I have a very strong feeling that the former is especially suitable for isomorphic applications and Flux applications in general.

Hope to experiment with it soon. Subscribe to issue #17 as well as I might post updates there.

@gilesbradshaw
Copy link

I've been looking at this issue with react-resolver I've changed it to use js-csp channels rather than promises. I'm thinking promises, streams, observables &c are all convertible to channels yielding data. So the server will just take one item from each channel whereas the client will take the first item then loop taking subsequent items till the component unmounts.

@RickWong
Copy link
Owner

RickWong commented Jun 4, 2015

@gilesbradshaw That sounds really interesting. Can you point me to the issue you're talking about?

@gilesbradshaw
Copy link

This is my branch using CSP - although it's a WIP currently it's equivalent to just using promises but next step is to allow the channels to 'keep on giving' https://github.com/gilesbradshaw/react-resolver/tree/csp

this is an app using it - it renders isomorphically https://github.com/gilesbradshaw/react-flummox

@tarqd
Copy link

tarqd commented Oct 8, 2015

I was working on a similiar library and this is the method I was toying around with for updates:

Essentially, you'd have a Query class that you pass to the Container. It is sort of like a light-weight component without the rendering. The plus here it supports updates via an event emitter. It requires bluebird since we need to cancel inflght queries if we get an update before the previous one completed (might be better to just queue them and execute them all by default).

// Base Resolver Class, handles creating a promise for given properties
// Also keeps track of the variables it depends upon
class QueryResolver extends EventEmitter {
  constructor(props,deps) {
    this.props = props || {};
    this.deps = (deps || []).slice(0);
    super();
  }
  setProps(nextProps, callback) {
    return this.doSetProps(nextProps, false, callback);
  }
  doSetProps(nextProps, force, callback) {
    var previousProps = this.props;
    this.fragmentWillReceiveProps(nextProps);
    var shoudUpdate = force || this.fragmentShouldUpdate(nextProps);
    if (shouldUpdate) {
      this.fragmentWillUpdate(nextProps);
    }
    this.props = Object.assign(this.props, nextProps);
    var promise = shouldUpdate ? this.getState() : this._state;
    return promise.asCallback(callback);
  }
  forceUpdate(nextProps, callback) {
    this.doSetProps(nextProps, true, callback);
  }
  fragmentWillReceiveProps(nextProps) {}
  shouldFragmentUpdate(nextProps) {
   // if the props object is the same, don't update
    if (nextProps === this.props) return false;
    if (nextProps != null) {
      // if any of the variables we depend upon have changed, do the update
      return this.deps.some((key) => {
        return nextProps.hasOwnProperty(key) && nextProps[key] !== this.props[key];
      })
    }
    // if all else fails, update
    return true;
  }
  // life cycle methods, can be overriden
  fragmentWillUpdate(nextProps) {}
  fragmentDidUpdate(prevProps) {}
  // called by container
  getState(callback) {
   // if we have a pending query, cancel it (bluebird)
    if (this._state) {
      if (this._state.isPending()) {
        this._state.cancel();
      }
    }
   // get the promise from the resolve function
   // ensure it is cancellable
    var currentState = this._state = Promise
      .resolve(this.resolve())
      .cancellable()
      .asCallback(callback);
    // we have changed, let the container know it needs to update it's state
    this.emit('change', currentState);
    return currentState;
  }
  resolve() {
    throw new Error('You have to override this method');
  }
}

The container would then keep track of all it's queries. When it receives a change event, it replaces the promise with the new one by calling QueryResolver#getState. The container reverts to the "loading" state until the promise is fufilled, rejected, or cancelled.

I don't think this is by any means the best way to do this, but it's an idea. I do like that the query now is responsible for checking if it should update instead of the container. We can probably lose the event emitter and replace it with an observable type that emits promises.

Edit:
Since it's not very clear here, containers should only call getState when they receive an update or are mounting. I'd actually probably change it so you can call getState anytime and it always returns the current state promise instead of calling resolve (only cancel if an upate is forced?)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants