cjohansen / form-app

Demonstrating how to build frontends around stateless, data-driven components
MIT License
9 stars 1 forks source link

Questions about data-flow #1

Open mateodif opened 1 month ago

mateodif commented 1 month ago

I'm very interested in this approach, but I'm having a hard time visualizing how to do some basic things like, for example, authorization and fetching data.

For authorization, I imagine the following:

  1. Render an AuthWrapper component, that takes an initial state with :authenticated? false and renders a login form
  2. Once the Login button from the form is clicked, perform an API call and change the state depending on the success of the auth. How would this be performed using asynchronous calls?
  3. Now the state has :authenticated? true and the AuthWrapper renders the main component instead of the login form
  4. The main component now would probably need external data from the API, how would this be done? Maybe using :on-mount?

I can't completely grasp how the complete data flow goes. Any suggestions on what to read, other examples, etc would be great!

Thanks :)

cjohansen commented 1 month ago

Thanks for the interest! The basic idea of this approach is to use the central data store as the main point of synchronization, for all data needs. I talk about this at some length in my talk (https://vimeo.com/861600197), although I don't go into a lot of detail on networking.

Here's roughly how I would solve an authorization flow using this approach. There would not be an AuthWrapper component, because the main idea is to only have visual components, and put the semantics of what they're asking the user for in pure data transformation code.

So, here's the rough flow:

  1. Look at my central data store (on the client - an atom or a Datascript database, etc). If there is no session in it, or if my information indicates that the session has timed out, I will render a login screen. The screen will use generic form-components.
  2. The login button will have an action like [:action/login "username" "password"]
  3. The implementation of the action (e.g. here) will add data to the store indicating that a login is in progress, then trigger a HTTP request to the backend.
  4. Because the data store now has data indicating that a login is in progress, I updated the rendered form by locking fields and displaying a spinner.
  5. When the HTTP request completes, I update the data store with the results.
  6. If the request resulted in a valid session, my data store now has a valid session in it, so I will render the main app screen instead of the login screen.

So everything coordinates through the data store, and the rendering logic always makes decisions based on what's in it. There are no components with networking in them, or domain-specific knowledge at all. Components are just generic rendering building blocks, and receives UI data prepared by a pure function (e.g. that transforms domain data to UI data).

Hope that helps!