omniscientjs / omniscient

A library providing an abstraction for React components that allows for fast top-down rendering embracing immutable data for js

Home Page:http://omniscientjs.github.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Async updates

adamschoenemann opened this issue · comments

I was wondering what is the best way to do async operations based on cursor updates?
I've reworked the real-time search example to use an async request to an API endpoint. This is what I've come up with so far:

var structure = immstruct({
    search: '',
    matches: [

    ]
});

structure.reference(['search']).observe('change', function() {
    fetch('http://taarn-net.dev/api/user/search', {
        method: 'post',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({name : structure.cursor('search').deref()})
    }).then(resp => resp.json()).then(json => {
        // console.log(json);
        structure.cursor('matches').update(() => Immutable.fromJS(json));
    });
});

Is this correct, or is there a better way? Anything I should be careful of?
Also, I was wondering if the Immutable.fromJS(json) is the smartest thing to do? updatedoes not appear to automatically convert from plain JS collections to Immutable.

Thanks for any feedback!

You can do it that way, but you'd need to throttle/debounce your requests (change callback) and maybe have some cancellation to not make a lot of extra API calls.

structure.reference(['search']).observe('change', debounce(function() {
    fetch('http://taarn-net.dev/api/user/search', {
        method: 'post',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({name : structure.cursor('search').deref()})
    }).then(resp => resp.json()).then(json => {
        // console.log(json);
        structure.cursor('matches').update(() => Immutable.fromJS(json));
    });
}));

You can also make this a function, to be able to re-use it, and you should return the changed value, making it more testable and composable. You have to remember that this will happen everytime you change search, though. If you clear the input, etc. You might also want to trigger the function manually through some trigger in your component.

function search(updateInCursor) {
    return fetch('http://taarn-net.dev/api/user/search', {
        method: 'post',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({name : structure.cursor('search').deref()})
    }).then(resp => resp.json()).then(json => {
        // console.log(json);
        return updateInCursor.set('matches', Immutable.fromJS(json));
    });
}

var debouncedSearch = debounce(search);

And call debouncedSearch as an action from your component, or use direct listeners as your example.


In regards to immutable.js: You'd have to wrap mutable object literals and js constructs to immutable.js objects. Immutable.fromJS might not be optimal, but it will convert "nested values" (lists in maps etc), but if you have control on what data you get, you might just want to use something like Immutable.Map or Immutable.List.of().

Thanks for your response! Those are valid considerations in general. But it seems that using observe on a reference in order to update state based on other state is not discouraged... Or is there an alternative you would suggest?

My initial thought is that it might make reasoning about your dataflow a bit harder. In that way it might be better to trigger the function from your component. This way you'd have your updating happening from your component instead of parallel to your component, if that makes sense. That being said, I can see some cases where something like this is favorable/handy. I'd say it kind fo depends on what you are comfortable with and what makes sense for the current use case.

Thanks for your answers, they were very helpful. I ended up moving the async operations into the component.

No worries. Happy to help