reactive-python / reactpy-django

It's React, but in Python. Now with Django integration.
https://reactive-python.github.io/reactpy-django/
MIT License
322 stars 18 forks source link

`UserModel` related hooks, decorators, and settings #190

Closed Archmonger closed 8 months ago

Archmonger commented 12 months ago

Description

Checklist:

Please update this checklist as you complete each item:

By submitting this pull request you agree that all contributions comply with this project's open source license(s).

Archmonger commented 9 months ago

@rmorshea I need your opinion on the use_user_data API. To save you some time, here's the short and sweet summary:

use_user_data allows you to store or retrieve data specific to the connection's User object. This user_data is persistently stored within the database and can be accessed like such:

from reactpy import component, html
from reactpy_django.hooks import use_user_data

@component
def my_component():
    # user_data properties: current, loading, error 
    # user_data callable attributes: refetch
    # set_user_data properties: loading, error
    # set_user_data callable attributes: __call__, reset
    user_data, set_user_data = use_user_data()

    # Here's an example that uses most of the API
    async def on_key_press(event):
        if event["key"] == "Enter":
            # User data is always a dict
            merged_data = user_data.current | {uuid4(): event["target"]["value"]}
            set_user_data(merged_data)

    return html.div(
        html.input({"placeholder": "Type some user data here...", "on_key_press": on_key_press}),
        html.div(f"Data: {user_data.current}"),
        html.div(f"Data Loading: {user_data.loading}"),
        html.div(f"Set Data Loading: {set_user_data.loading}"),
        html.div(f"Error(s): {user_data.error} {set_user_data.error}"),
    )

To get the conversation started, here's a few questions/concerns I have:

  1. Does it make sense that user_data.current returns a dict?
  2. Does splitting the interface into user_data, set_user_data feel right?
  3. Is the set_user_data interface clear and logical? The interface is identical to use_mutation.
  4. Is the user_data interface clear and logical? This interface is different than use_query interface in the fact that the data attribute was renamed to current (user_data.data looked weird to me).
rmorshea commented 9 months ago

I'll try and take a look in the next couple days.

Archmonger commented 8 months ago

Would you have time to look at the interface proposed in the above comment this weekend?

This PR is fairly bulky and has a lot of Django-only jargon, so a PR review won't be needed.

rmorshea commented 8 months ago

Sure. I'll make time today or tomorrow.

rmorshea commented 8 months ago

My take is that the marginal UX improvements made by creating special wrappers for the query and mutation objects may be outweighed by requiring the user to learn something new. It seems easier to explain to the user that use_user_data returns a tuple with a query and a mutation.

To address some of the usability concerns in a slightly simpler way, we could consider adding a __call__ method to mutations and returning a named tuple from use_user_data so usage would be

user_data = use_user_data()

# access data
user_data.query.data

def some_callback():
    new_user_data = user_data.query.data | {...}
    user_data.mutation(new_user_data)
Archmonger commented 8 months ago

Agreed, will implement soon.