Skip to content

UseStateHandle can become stale #2112

@mc1098

Description

@mc1098

It was mentioned in #2109 about how the UseStateHandle can contain stale data - this is the case because in use_state we replace the Rc<T> on each set which means any Rcs that handles are holding are now stale. The handle keeps the Rc in scope so it will always be valid but this isn't what most people would expect.

The reason this goes somewhat unnoticed is that we often re-create Callbacks so will move in the updated UseStateHandle so that the value is valid, however, when you pass it to something like an Agent or the router listener callback then it is a single Callback that never gets updated and whatever the state was when that handle was passed in is what it will remain to be.

So solving this issue is actually bit difficult without causing ergonomic pain (unless I'm missing something, and I hope I am). If we used a Rc<RefCell<T>> with use_state and then encapsulated that in the UseStateHandle then our state could remain in sync which is good.
We would have to make sure that users of handle could not mutate the state other than the set fns. UseStateHandle could no longer impl Deref and would have to have a borrow function like RefCell so we could enforce the borrow lifetime constraints for exclusive mutability when we actually run the setter. I think if we uphold the lifetime constraints we can guarantee that we won't panic when trying to get a mutable borrow of state.

We could dip our toes into some unsafe 👀 and use UnsafeCell in order to still impl Deref and avoid the RefCell runtime borrow checks - I haven't thought too much on the safety argument but I think it would be safe to do this as we'd only give out references to T with a lifetime that is bound to the UseStateHandle so would prevent someone from deref -ing state then passing it to a Callback as they all require 'static lifetimes. We can then happily mutably borrow the state in the setter because this is within the scheduler so we can't have outstanding borrows to state because we require 'static lifetimes to store anything.

I'd love to hear from others regarding the above and whether I missed something or if there is a better way to it all :) We can either try and resolve it or document it - but the latter would be a shame because I think this behaviour will catch people out.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-yewArea: The main yew crate

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions