🏠 back to Observable

New tool to use React with Observable

Hello!

I’ve created a notebook that provides some helpful tools to to create and render React components with Observable.

Here’s what it does:

  • There’s a jsx function that uses the htm library to allow you to use JSX-like syntax directly in Observable.

  • You can call render to render some JSX to the page

  • You can call component to create a component that maintains its identity even if values used by the component change. This is accomplished by storing the returned component object in a cache keyed by the original component’s source code.

  • I’ve also created wrappers for memo and forwardRef that use the same implementation

  • Finally, virtually all the React exports have been re-exported for easy use:

    import { jsx, component, render, useState } from '@j-f1/react'
    

    (You can still import the original React and ReactDOM objects if you like)

What do you think? Are there any fatal flaws with this method?

4 Likes

Super cool, I especially love the React-inspired secret constant name :slight_smile: - I’ll add a link from my React-related notebooks.

2 Likes

Note that this

htm = (await import('https://unpkg.com/htm@2.1.1?module')).default

doesn’t work in current Firefox (but should work at some point in the future).

Is that because it doesn’t support ES modules yet?

It can be made to work in Firefox 66 by setting javascript.options.dynamicImport to true in about:config: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Browser_compatibility

It looks like dynamic imports will be enabled by default in Firefox 67 (due to be released in May).

2 Likes

Would you be willing to add that information to the notebook in the form of a suggestion?

I’ve just updated the notebook:

  • I’ve removed the dynamic import call.

  • The internal API has mostly been rewritten.

  • The render function now has support for viewof:

    viewof foo = render(({ useSetter }) => {
      const [text, setText] = useState('')
      useSetter(text)
      return jsx`
        <input
          type="text"
          placeholder="..."
          value=${text}
          onChange=${event => setText(event.target.value)}
        />
      `
    })
    
    foo // is the value of the text input