hybridsjs / hybrids

Extraordinary JavaScript UI framework with unique declarative and functional architecture
https://hybrids.js.org
MIT License
3.05k stars 85 forks source link

store.error() Guard does not work with enumerable Models loaded from asynchronous storage #221

Closed Qsppl closed 11 months ago

Qsppl commented 11 months ago

Example https://codepen.io/qsppl/pen/PoVyQvK?editors=0010

image

Defender works if you use synchronous storage.

I can't find in the documentation why this happens.

https://hybrids.js.org/#/store/usage?id=storeerror

When I return an error as in the documentation, the component stops working. image

And the render function returns nothing. image

smalluban commented 11 months ago

Here you have fixed example from the codepen:

import { define, html, Model, store } from "https://esm.sh/hybrids@8.2.5"

const CommentStore = {
  id: true,
  body: '',
  [store.connect]: (id) => fetch(`https://jsonplaceholder.typicode.com/comments/${id}`).then(res => {
    if (!res.ok) throw Error(res.statusText);
    return res.json();
  }),
}

const usersSource = [{
  id: 0,
  name: 'lorem ipsum gamma',
  comments: [-1, 0, 1, 2],
}]

const UserStore = {
  id: true,
  name: '',
  comments: [CommentStore],
  [store.connect]: (id) => usersSource.find(item => item.id === Number(id)),
}

define({
  tag: 'comments-list',
  user: store(UserStore),
  render: ({ user }) => html`
    ${store.ready(user) && html`
    User ID ${user.id} ${user.name}
    <br>Comments:
    ${user.comments.map(comment => (store.ready(comment) || store.error(comment)) && html`
    <br><br>
    Comment ID ${comment.id} ${store.error(comment) && '[error]' || '[ok]'}<br>
    ${store.ready(comment) && comment.body}
    `)}
    `}
  `,
})

The store guards simplifies (but they might work differently than in other systems, so this at first can confuse) access to the model:

If you want to display some information when the model is resolved (regardless if it is fine or not) you must use both guards: store.ready() || store.error(). However, then you have to protect access to model properties in nested code, as they might not be accessible.

I made as less as possible changes to your code to make it work, but guards could be set a little bit differently for the clarity:

// comment map fn html
${store.error(comment) && html`comment error: ${store.error(comment)}`}
${store.ready(comment) && html`comment body: ${comment.body}`}
Qsppl commented 11 months ago

thank you, now I understand.