ManuelDeLeon / viewmodel-react

Create your React components with view models.
MIT License
24 stars 3 forks source link

Autorun problems when props change during loading process #39

Closed davidsavoie1 closed 6 years ago

davidsavoie1 commented 6 years ago

Hi Manuel!

When components are loaded conditionally (either one or the other), if the prop that controls which one is loaded changes too early in the loading process, autoruns seem to stop working, with strange behaviors.

App({
  render() {
    return (
      <div>
        {this.content()}
      </div>
    );
  },

  content: () => ({
    started: <Started />,
    ready: <Test />,
  }[this.status()]),

  status: 'started',
});
Started({
  render() {
    return (
      <div>
        <h1>I just started!</h1>
        <p>GIve me a break....</p>
      </div>
    );
  },

  created() {
    this.parent().status('ready');
    console.log('<Started /> created');
  },
});

In this example, if the status changes when the <Started /> is created, then <Test /> is rendered, but is not working properly. Here's a repo that reproduces the error. Of course, in real life, this kind of problem occurs when Meteor variables change real quick (subscription is ready, user info gets sent, etc.).

Is there something that can be done to prevent such behavior? Routing is probably something I will look into, but I don't think it will solve all problems... It seems to be linked to the problem I signaled in this past issue.

davidsavoie1 commented 6 years ago

Just to give some more context, here's my real world case. When my app starts, I check if the user is logged in. If he is, I also check if he has admin rights. The app could then be in either one of three states (status):

The problem is that at startup, the user is considered logged in, but the info concerning admin rights seems to arrive slightly late and the user is considered a regular one at first. State is then 'userLoggedIn'. As soon as the admin status of the user gets received, the status changes to 'adminLoggedIn' and the proper page (the one I expect) gets rendered. Apart from the sometimes perceptible glitch in rendered views, it seems to be working fine.

However, the delay is so small between both renderings that autoruns get wrecked somehow. I then get, as an example, an input box that will update the binded prop correctly, but will not change its display if the prop value itself is changed by any other mean. That's what I'm simulating in the reproduction, when I change the parent status on the child's created hook.

I'll need help on this one, please!

ManuelDeLeon commented 6 years ago

If I understand the issue correctly this isn't a problem with ViewModel. What I've done in the past is rely on spinners to wait for the data to arrive to the client. Last time I checked Meteor's SSR didn't provide a way to SSR a page with user data either.

davidsavoie1 commented 6 years ago

Hi Manuel!

Thanks for the reply. I do want to use spinners when I can, it makes a lot of sense. The problem I get in this case though is that it seems to be related to data which doesn't have a ready handle to determine if it has been received (the user admin status, defined with alanning:roles).

Is there a way to avoid too fast recalculation of props values that breaks autorun behavior?

Oh well, I'll try harder then! Thanks anyway. I hope I can find ways to avoid such pitfalls...

ManuelDeLeon commented 6 years ago

The first thing I would try to do is get rid of the autoruns altogether. They're rarely needed. In the case of a component waiting for data from a subscription or another source, I usually just have a ready property that I turn to true when the subscription or promise resolves/finishes, and on the template I show a spinner if that property is false, the data if true.