Giter Site home page Giter Site logo

first class classes about react-haskell HOT 8 OPEN

joelburget avatar joelburget commented on June 3, 2024
first class classes

from react-haskell.

Comments (8)

johncant avatar johncant commented on June 3, 2024

Can we have a composition tag reactClass_ to bridge the gap between ReactT and ReactClass in an obvious way?:

haskell
div_ $ do
reactClass_ someClass
span_ "this is not a class"

from react-haskell.

johncant avatar johncant commented on June 3, 2024

^ I see your point about createClass living in the IO monad from trying to use the above example

It looks like the Javascript render function on each React class is being short-circuited and it needs to work in order for a React class to work when instantiated using createElement(someClass). Also, it looks like the state is currently associated with each class, whereas it should be associated with each class instance, which should all get created by React. React already has a place for storing state, so wouldn't it be correct to store the Haskell state as a key inside the JS state?

About to do some more hacking........

from react-haskell.

johncant avatar johncant commented on June 3, 2024

Where do animations and transitions fit into Javascript React?

from react-haskell.

joelburget avatar joelburget commented on June 3, 2024

Yeah, I think something like reactClass_ is the right way to approach rendering classes. I might want to reuse locally.

With 0.13b1 React.createClass is no longer required, which makes it less awkward to move class creation out of the IO monad.

I'm currently thinking of classes in react-haskell slightly differently than classes in React proper. Each one is sort of a standalone root like you might see in flux controller-views. The idea being you can isolate different parts of the tree so the whole thing doesn't have to rerender.

So react-haskell is much more prescriptive than regular React because it builds in (soon) controller-view components, transitions, and animations. I think in the future I'd like to separate these different things into their own packages (along with routing, etc), but for now it's most convenient to develop them in the same package.

As far as state vs props, they're operationally the same for top level components, but I think it's slightly clearer to use props.

Was that all reasonable?

from react-haskell.

johncant avatar johncant commented on June 3, 2024

I've been working on a branch which uses a reactClass_ as a starting point - it can always be done away with later. The unmonadic class creation helps massively. Although, couldn't we just not use the IO monad, since class creation is effectively instant and doesn't have any side effects (I couldn't think of any)?

But surely you still want to be able to compose them? Does a state change in a component cause all of its parent components to rerender?

I think your approach to these extensions is reasonably sound. With animations, I sort of abandoned them in order to get composing classes working. I'll hopefully be able to bring them back in as an extension in a separate module, but this package. I'll need to do that before submitting a pull request because otherwise my hacking would decrease the functionality in this repo.

from react-haskell.

joelburget avatar joelburget commented on June 3, 2024

couldn't we just not use the IO monad, since class creation is effectively instant and doesn't have any side effects

Yep!

But surely you still want to be able to compose them?

Yes. Here's what I'm thinking. reactClass_ and locally are almost equivalent, but the former takes a ReactClass and the latter takes a ReactT.

With locally, you're embedding a "dom fragment". It has no embedded knowledge. The class is still responsible for handling transitions and animations.

With reactClass_, you're embedding a class, which has embedded knowledge. The child class handles its own events like normal. But the parent class also handles events the child class emits. I think this means we need to add another variable to ReactClass so it has a notion of both internal and external signals - ie those signals which it handles and those it emits. Emitting a signal only happens in response to handling a signal (by the way, I'm being sloppy with the terms "signal" and "transition" - I mean the same thing by both). render only renders classes that emit Void - ie never emit signals.

Does a state change in a component cause all of its parent components to rerender?

No. In the formulation I'm picturing a class means two different, but related things:

  1. It's a conceptual whole. An abstraction. Examples: search box, map, etc.
  2. It batches events and animations. It's a hub for state changes that might be contained. In the map example, most interactions and animations are probably handled within that class, without ever alerting the map's parent of user interaction.

My observation is that work (events and animations) can often be contained within an abstraction. Like in the map example - we can contain all that work to within the map. I propose intentionally conflating the two meanings of classdom in ReactClass because more often than not they roughly coincide.

Now, we can limit work to within a class except for when the child emits an event.

from react-haskell.

joelburget avatar joelburget commented on June 3, 2024

Two things I need to think about / come to terms with:

1. uni-directional data flow

In the flux architecture uni-directional data flow feels like an improvement over plain React. We have something similar-ish at the moment, but only because we can't nest classes (which is definitely a bad thing). React-haskell signals and flux actions are roughly the same. They transition the store (there's only one in react-haskell, it's the top-level state).

Now, it feels like an improvement over the current state of affairs to be able to nest classes, selectively emitting events from child classes, hiding irrelevant state. However, if you squint we've arrived right back at the original React architecture, with props being passed in and state within the class. The difference is we're emitting events rather than taking callbacks. But still, I guess that means we've lost uni-directional data flow, since we need to handle signals at every level in the hierarchy.

I don't think the situation is quite as bad as that, which I can elaborate on later when I've thought about it more and am less tired.

2. hidden state

Nesting classes also (if we do it wrong) introduces hidden state, which is definitely not good. One of my design requirements is that you can serialize the entire state of the app. Preferably you can serialize the entire history of the app. Every transition that's ever happened. Would make debugging so much easier.

Note: I've taken a small step away from this world with animations. They're treated as inconsequential state which would be ignored in serialization. I think that's okay.

Where I'm looking for inspiration:

from react-haskell.

johncant avatar johncant commented on June 3, 2024

I took a look at this to get more insight: https://github.com/ianobermiller/nuclearmail/blob/master/src/js/ThreadView.js and made some notes mainly to help my own understanding:

React:

  • props and handlers flow down the React DOM
  • state is stored in each React Class
  • Data can only move up the DOM when event handlers cause a state change higher up.
  • Data flows down the React DOM through props and state, then at different points in the DOM, it can jump directly upwards into the state of any React Class through events, including its own React Class.

Flux:

  • props flow down the React DOM, but handlers are not passed down between React Classes.
  • state is stored externally to the React DOM.
  • Data can only move up the DOM when the event handlers aka actions trigger the external state to change, which causes the whole React DOM to rerender.

End of notes

Is hidden state required?

If you want to let people use react-haskell in a non-Flux-like way, composing classes, then yes. If you only want to only let people use a Flux-like architecture, then no, unless performance of rerendering the whole React DOM or copying most of a large immutable object is likely to become a problem, in which case yes.

I'd suggest allowing hidden state to exist, and leaving it up to the application as to whether to use it. I'd advocate having a ReactClass that mapped as closely as possible to a JS React Class, and exporting an alternative ReactClass in a module maybe called React.Flux where state could always be (), thereby banning hidden state. An application that used a flux architecture with react-haskell could then more conveniently use React.Flux.ReactClass, not have to worry about state or child handlers, and always be able to serialize its entire state.

This breaks transitions a tiny bit though, because they can no longer just act on the state of the component, instead they have to act the state of some global datastore.

from react-haskell.

Related Issues (19)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.