Git Product home page Git Product logo

Comments (6)

idream3 avatar idream3 commented on May 20, 2024

more mind dumps...

It would actually need to be closer to this:

cerebral.watch('authors', function(data [, uuid, path2...]) {

 // ok, no data. We need to get it from server so add isLoading
  if (!data) {
    let data = {
      $isLoading: true
    };

    // we have an extra keypath so we need to be more specific
    if (uuid) {
      data.id: uuid
      cerebral.signals.missingAuthor(uuid);
      return data
    }

    // else we make the basic call
    cerebral.signals.missingAllAuthors();
    return data
  }

  return data
})


// then it would cater for each use case
var author = cerebral.get('authors', uuid)

var authors = cerebral.get('authors')

from cerebral.

christianalfoni avatar christianalfoni commented on May 20, 2024

Hi @idream3 ,

You raise an important question here. What I value most of all is to keep the code readable and easy to compose in your head. Adding a concept of watch would make it harder to compose how the application works. You have your cerebral state, your maps and also this watcher. How they interoperate is just difficult I think, as they are very decoupled.

I do see your concern of keeping DRY code, but you could quite easily do something like:

var setOrGetAuthor = function (cerebral, id) {
    let author = cerebral.get('authors')[id];
    if (!author) {
     author = {
        id: id,
        $isLoading: true
      };
      cerebral.signals.missingAuthor(id);
    }
    return author;
};
cerebral.map('visibleTodos', ['todos', 'authors'], function (cerebral, uuid) {
   let todo = cerebral.get('todos')[uuid].toJS();
   todo.author = setOrGetAuthor(cerebral , todo.authorId);
})

And you could just reuse that function across all mapping.

I think we need more experience before implementing a brand new concept at least, but thanks a lot for the input :-)

from cerebral.

idream3 avatar idream3 commented on May 20, 2024

Ok, I agree that another concept abstraction is probably not the way to go.

Your code above illustrates nicely how you could inline for a single use case and wrap into a generic function for multiple cases. I would be inclined to have a general file called getOrFetch.

And then:

cerebral.map('visibleTodos', ['todos', 'authors'], function (cerebral, uuid) {
   let todo = cerebral.get('todos')[uuid].toJS();
   todo.author = getOrFetch.author(cerebral , todo.authorId);
  return todo
})

The benefit of leaving it how it is gives us developers more flexibility :)

This does, however, remind me of another concern I have about data fetching. Literally all of the data in my application is fetched from a server and I suspect this will be the case for most applications (or local storage etc...). Data fetching works well within Maps but how to fetch data for a single path elegantly?

Take this for example:

var state = {
  projects: {},
  users: {}
  templates: {}
  notes: {}
}

All data needs to be fetched from the server. In my current Flux implementation most of the requested data fetching is handled by the store if the data does not exist (exactly like the Map function above). You can do this because you define the get methods on the store like getProjects, getUsers etc...

But for single key paths in Cerebral how do you do this with out having a pseudo getter for each one:

Cerebral.Map('getProjects', ['projects'], (cerebral, state) => {
  if (!state.projects) return getOrFetch.projects();
  return state.projects
})

Hmmm, but then this wouldn't even work because you are concerned with the initial load of data and in this case 'getProjects' Map wouldn't even trigger because the 'projects' path will not fire a change when the (React) component is mounted.

Now then, I see two options as a start:

  1. add a signal into componentWillMount (initialize)
componentWillMount() {
  if (!this.state.projects) this.signals.missingProjects()
  if (!this.state.users) this.signals.missingUsers()
},

render() {
  if (!this.state.projects || !this.state.users) return <Loading/>
}

But it seems to me that the components should just ask for the data and not be concerned about requesting for missing data.

Also the code above is something that should go into Higher-order components. Perhaps we implement something like Baobab-react. (create a separate issue?).

  1. Implement something akin to my first comment - a function that runs after 'getting' a path.
Cerebral.afterGet('projects', value => {
  if (!value) signals.missingProjects()
  return value
})  

Or, perhaps we can use the Map here. The Map function runs when either of the paths have changed/update, maybe if the second paramter is a function it will run the Map function after the using the 'get' function.

Cerebral.Map('projects', value => {
  if (!value) signals.missingProjects()
  return value
})  

Not sure if any of this feels like the right way to go about it... I will keep experimenting with this aspect.

from cerebral.

christianalfoni avatar christianalfoni commented on May 20, 2024

Hi @idream3 and again thanks for input :-)

In this scenario I would suggest this:

let getInitialData = function () {
  return Promise.all([getProjects, getTemplates, getUsers]);
};
cerebral.signal('applicationRendered`, getInitialData, setInitialData);

And this signal would trigger on the componentDidMount of the root component. This way you can reuse the getProjects etc. function on other signals. I am skeptic to creating too much automation as it is difficult to reason about when things trigger. I think it is an important concept in Cerebral that all state change is handled with a signal.

This actually got me to thinking:

cerebral.signal('applicationRendered`, [getProjects, getTemplates, getUsers], setInitialData);

It would be possible to indicate that these actions should run in parallell and when all are done, go to next action. What do you think?

Anyways, your suggestion on using map would also work.

from cerebral.

idream3 avatar idream3 commented on May 20, 2024

Great stuff, I like the parallel addition.

I actually think now that it does make sense for a component to send a signal on mount that it needs data if missing.

I am going to experiment with this in my higher order components and see how we go.

Thanks for your feedback :)

from cerebral.

christianalfoni avatar christianalfoni commented on May 20, 2024

Cool! I will just close this for now. Create a new issue if new questions related to this pops up :-)

from cerebral.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.