question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

RFC: stateful functional components (aka "hooks")

See original GitHub issue

React announced support for hooks.

This idea is an interesting alternative to class-based components, offering many of the same benefits (control state, in particular) while composing considerably better than class-based components.

I’ve argued in the past for some sort of stateful component (because controls have control state that’s only relevant while they exist) and this seems like a nice trade-off, providing a means of maintaining state without providing a complete different concept that often forces people to factor back and forth between stateful and stateless components.

Background

The basic idea is illustrated here:

The difference between class-based and hook-based components is illustrated here:

You can watch Dan Abramov give a full presentation here.

Proposal

I’m proposing only state and effect hooks for now, as these cover a lot of ground. (I’d like to explore the possibility of introducing shared state contexts, and possibly effects, at a later time.)

State Hook

What I’m proposing for state management is slightly different from what the React RFC proposes. It relies on call-order for identity, which seems really brittle - I’m instead proposing that any hook will need to explicitly define in advance the unique states that may be used within a component.

Here is a counter example:

const useCount = createState()

function Counter() {
  const [count, setCount] = useCount(0)

  return (
    <div>
      Count: {count}
      <button onclick={() => setCount(count + 1)}>+</button>
    </div>
  )
}

In this example, useCount = createState() creates a state hook with no initial state, and therefore, the call to the useCount() function must supply the initial value 0.

Creating a pre-initialized state hook would also be supported:

const useCount = createState(() => 0)

function Counter() {
  const [count, setCount] = useCount()
  // ...
}

In this example, useCount = createState(() => 0) creates a state hook with a built-in initialization function, so the call to useCount() requires no initial value.

Implementation Notes

The internal functions likely need to change in several ways.

Most importantly, the aggressive calls to functional components in the h() function need to be deferred, such that a Function is now regarded (in terms of diffing and patching) as a VNode-type (currently called name) on par with e.g. "div" - the actual calls to functional components would need to happen during the diff/patch itself; as late as possible, rather than (as is now) as early as possible.

Since we’ll need to track component instances, we’ll need to store these instances somewhere. Storing them in DOM elements won’t work, since the functional component isn’t an element (and doesn’t contain elements before we invoke the functional component) so I suggest storing them in a Map, since this allows the use of the state hooks (useCount etc.) themselves as keys.

I’d suggest functional components should support life-cycle callbacks, since keyed updates will become important - if we treat the functional component occurrence like an element in terms of diffing/patching, then key will come into play, since otherwise we can’t discern component instances.

Likewise, I’d suggest supporting the full range of life-cycle hooks oncreate, onupdate, onremove and ondestroy for functional component instancse - and since they have no single corresponding DOM element, I’d suggest passing the Map instance to e.g. oncreate instead of an HTML element.

As for where to store these Map instances between renders, I’d suggest the patch() function return a modified VNode-tree with component instance references. Currently it returns the input VNode-tree exactly as provided - it would likely need to inject the Map as e.g. vnode.instance in the returned VNode-tree for subsequent patching/diffing.


I obviously haven’t worked out all the details, so these are just some preliminary ideas.

I’d love to attempt this myself, but I’ve had no luck with this in the past, and I’m pretty sure I’d fail and get frustrated, so for now I’m just posting the idea 😉

Thoughts?

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
jorgebucarancommented, Oct 29, 2018

@mindplay-dk Sorted by less abstract to more abstract: Superfine → React → Hyperapp

Superfine is a low-level library. It is only the view layer whereas React is a view layer and a primitive state container, usually enhanced through more advanced state containers (managers) like Redux, Mobx, and so on.

Do Hooks mix with React? Yeah. Do Hooks mix with Superfine? Not really. There’s not even a concept of state in Superfine.

Now, should we introduce a primitive state container to Superfine? I don’t think so. I’m already working on a JavaScript framework that has opinions about views and state management and I’d prefer to keep Superfine as minimal as possible.

Hyperapp+Hooks? That’s another issue. 😉

0reactions
k1r0scommented, Nov 28, 2018
Read more comments on GitHub >

github_iconTop Results From Across the Web

Stateful functional components — React Hooks - Medium
The first type is the class-based components which are also known as “stateful components”, “smart components” or “containers”.
Read more >
Introducing Hooks - React
With Hooks, you can extract stateful logic from a component so it can be tested independently and reused. Hooks allow you to reuse...
Read more >
React Hooks Fundamentals for Beginners - freeCodeCamp
React Hooks are simple JavaScript functions that we can use to isolate the reusable part from a functional component. Hooks can be stateful...
Read more >
What you need to know about the React useEvent Hook RFC
In this article, we'll explore the useEvent Hook from React, which allows you to define an event handler with a function identity that...
Read more >
The Wise Guide to React useState() Hook
React useState() hook manages the state of functional components. ... a functional component with state, aka stateful functional component.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found