MithrilJS / mithril.js

A JavaScript Framework for Building Brilliant Applications
https://mithril.js.org
MIT License
14.02k stars 925 forks source link

[rewrite] Documentation of how auto redraw works #1438

Closed inuwan closed 7 years ago

inuwan commented 7 years ago

The doc for the rewrite version is very helpful. However, one area of confusion for me (having used the v0.2.x) is how auto redraw works in the rewrite.

In version 0.2.x, the m.request triggered a redraw if options.background = false, when the request completed. Does m.request still trigger an auto redraw? Looking at the source code, it seems like it doesn't?

Also m.startComputation and m.endComputation are no longer available in the rewrite, I did not see any mention of this in the migration document.

ghost commented 7 years ago

@inuwan What is your use case for m.start|endCompuation? I brought this up in gitter a while ago and was told it was code smell.

I build web-view based mobile apps that mirror native components with mithril 0.2. It has been necessary to be aware of every redraw to ensure a smooth user experience. Even a single excess redraw could cause an animation or transition to perform poorly. start|endComputation was essential to preventing these issues.

I was told this will not be a problem in 1.0. I have my doubts, but I am starting on the 1.0 port tonight.

inuwan commented 7 years ago

Agree. Was just pointing out the migration document (https://github.com/lhorie/mithril.js/blob/rewrite/docs/v1.x-migration.md) provides no mention that start/endComputation has been eliminated.

lhorie commented 7 years ago

[note: I edited the comment above to remove noise generated by email]

fmoens commented 7 years ago

Not sure whether this is related but here 's my question:

Looked at: https://github.com/lhorie/mithril.js/blob/rewrite/docs/request.md#typical-usage to try and display some data from a Rest backend, code is below. It turns out the data are not shown after the Ajax request returns, contrary to what I read on the 'Typical usage' page: "Once the request to the server completes, the array of objects items is assigned to Data.todos.list and the component is rendered again, yielding a list of divs containing the titles of each todo." I tried adding a call to m.redraw, to no avail. Am I missing something?

var Data = {
    books: {
        list: [],
        fetch: function () {
            m.request({
                method: "GET",
                url: '/api/books'
            }).then(function(data) {
                console.log('got data from server');
                Data.books.list = data.data;
                m.redraw();
            });
        },
    }
};

export const Books = {

    oninit: Data.books.fetch,

    view: function (vnode) {
        console.log('view');
        return Data.books.list.map(function (book) {
            return m("div", book.title)
        })
    }
};
barneycarroll commented 7 years ago

@inuwan everybody somehow got the impression m.request no longer triggered redraws on resolution. Turns out we were all wrong - it was there all along! 😮 There's a pull request at #1440 for more detail on changes to autoredraw and how redraw locks have been removed.

@fmoens it depends on your data. The example references an imaginary 'todos' API, yours refers to 'books'. Here's a jsbin I jotted up that does the same, with 'users' - when requests don't seem to work I often find it's because I've forgotten the shape of the data - ie in my example I need to access the data property of the response object to get the list I'm after. Logging the whole response usually helps.

fmoens commented 7 years ago

Should have given more info, sorry:

My router has the following:

m.route(document.getElementById('main_content'), "/", { "/": home, "/users": Users });

Let's say we start from the home page, where I have a link to users:

m("a.nav-link[href='/users']", {oncreate: m.route.link}, "Go to users")

My JS code now looks like:

var Data = {
    users: {
        list: [],
        fetch: function() {
            m.request({
                method: "GET",
                url: "/api/books",
            })
                .then(function(response) {
                    console.log(response);
                    Data.users.list = response.data
                })
        }
    }
};

export var Users = {
    oninit: Data.users.fetch,
    view: function(vnode) {
        console.log('view');
        return Data.users.list.map(function(item) {
            return m("div", item.title)
        })
    }
};

What happens when I click the "Go to users" link is that the view gets rendered, the rest call get its data from the backend (in that order) and that's it - no re-render of the view, no data displayed. Now, when I click the "Go to users" link once more, the view re-renders and the data are shown. (no backend call is executed in this case).

I've added timestamps to the titles (backend) to try and make sense of it: What happens:

  1. Starting from the home page, I click "Go to Users" -> No data displayed.
  2. I click on "Go to Users" again -> data displayed, no backend call.
  3. I click on "Home Page"
  4. I click on "Go to Users" -> data (from previous backend call) displayed, new backend call is executed.
  5. I click on "Go to Users" -> data (from last backend call) displayed, no backend call is executed.

Seems to me the redraw does not happen after an m.request.

I don't understand why your jsbin does work.

barneycarroll commented 7 years ago

@fsmoens OK, that is weird. I'll have a go at trying to replicate later on.

fmoens commented 7 years ago

Never mind, Barney, my mistake. Was serving mithril.js from the server twice from different locations. Sorry about that.

Filip

dead-claudia commented 7 years ago

Note that the autoredraw semantics for m.request still could use some documentation. :smile:

lhorie commented 7 years ago

Added some docs for auto-redraw