Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updated() broken? #397

Open
nerdoc opened this issue Apr 4, 2022 · 9 comments
Open

updated() broken? #397

nerdoc opened this issue Apr 4, 2022 · 9 comments
Assignees

Comments

@nerdoc
Copy link
Contributor

nerdoc commented Apr 4, 2022

I experience problems with the component's update() method. I created a simple test component, with one counter property and an inc() method. And to update* methods:

class FooView(UnicornView):
    counter: int = 1

    def inc(self):
        self.counter += 1

    def updated_counter(self, value):
        print(f"updated_state: {value}")

    def updated(self, name, value):
        print(f"updated: {name}, {value}")

The html is just the {{ counter }} and a button that calls inc().

Now, after first launch (counter=1) I would suspect that after clicking on the button, counter becomes 2, and the server should output 2 lines:

updated: counter, 2
updated_counter: 2

But instead, it outputs:

updated_counter: 1

Problems:

  1. The updated() method is never called
  2. The updated_counter() method always outputs the last (!) value - the one before the change happens.

If i add another button with set unicorn:click="counter=4" in the button, and click oce the first (inc) button, and then that one, the output is:

updated_counter: 2
updated_counter: 4
updated: counter, 4

Ok, so after setting the property per frontend, at least the updated() method is called. But I would expect that when I do a self.counter += 1 too.
And I don't know why the updated_counter: 2 even is printed there. That's too late, it looks like it would have been waiting in a queue somewhere?

I tried unicorn 0.44.1, 0.42.0, 0.40.0, 0.37.0 just to get a few versions
Any clues? Am I doing something terribly wrong, or is this a (really severe?) bug?

@nerdoc
Copy link
Contributor Author

nerdoc commented Apr 4, 2022

What I forgot: the context (and hence {{ counter }} is updated correctly in the visible HTML. Just the value in updated*is lagging behind.

@roman-tiukh
Copy link

I have same problem

@adamghill adamghill self-assigned this May 14, 2022
@adamghill
Copy link
Owner

Thanks for reporting, let me take a look. I have a theory, but I want to investigate some more to see what is going on.

adamghill added a commit that referenced this issue May 14, 2022
@adamghill
Copy link
Owner

Ok, so what is happening is this:
updated_* and updated were originally only designed to fire when setting a component's property from the front-end. It was mostly a way to tie a change in the template to something in the component. If you are already in the component writing code, I'm trying to to figure out how useful this would be. However, can you tell me more about what you are trying to do to make sure I understand the use-case?

One worry I have is that it could create an infinite loop in some situations. For example, if updated_counter had self.counter += 1, but I think I could figure out an ok approach for that.

@nerdoc
Copy link
Contributor Author

nerdoc commented May 14, 2022

I was changing the value from the front-end - just by clicking the "inc" button...

@adamghill
Copy link
Owner

I understand that. What I meant was setting a component property from the frontend, i.e. <button u:click='counter=2'>set value</button> as opposed to calling a component method. updated_ was designed to give a hook in the component code when a value changes in the frontend. Why would you need updated_* called after a component method is updated in the component?

@nerdoc
Copy link
Contributor Author

nerdoc commented May 15, 2022

sure, one can call it manually if needed.

@roman-tiukh
Copy link

roman-tiukh commented May 15, 2022

I would like to know when the value of a particular state has changed through updated_*, but I have this method called before and after hydrate(). Calling before hydrate() gives the old values and is called every time the component hydrates, whether or not the value has changed, and calling after hydrate() gives the already changed value.

I would suggest having something like changed_* so that you can react to changes in the state of the component.
And I would also suggest that the component have a private property _is_hydrated so that you can understand if the updated_* method was called before or after hydrate().

@adamghill
Copy link
Owner

@roman-tiukh That's interesting! Any chance you can fork #407 and provide some code that I can use to replicate? Ideally with some comments for what you would expect to happen as well. Or add some failing tests to show your expectations. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants