slinky icon indicating copy to clipboard operation
slinky copied to clipboard

React 16.6 feature support

Open shadaj opened this issue 6 years ago • 6 comments

  • [x] React.memo (more generally, explore functional component support?)
  • [ ] React.lazy (deferred indefinitely, does this have meaning in Scala.js where bundle splitting does not exist?)
  • [ ] static contextType (deferred indefinitely due to complex typing requirements, ping me if you need this!)
  • [x] static getDerivedStateFromError (in 0.5.1)
  • [x] Suspense component (in 0.5.1)

shadaj avatar Oct 24 '18 02:10 shadaj

static contextType will be awesome! Currently, we have several wrapper components whose sole purpose is to grab a context value and pass it as a prop to the underlying component (so that the underlying component can use it in componentDidMount and such lifecycle methods).

ramnivas avatar Oct 24 '18 02:10 ramnivas

The remaining two features are generally pretty incompatible with Scala (typing) / Scala.js (dynamic imports), so going to close this issue for now.

shadaj avatar Feb 10 '19 20:02 shadaj

@shadaj I'm wondering does it make sense to reopen this for enabling React.lazy now that Scala.js has supported code-splitting for a while?

My slinky app is starting to get slooow, so I was hoping to use React.lazy presuming scalajs-bundler can handle the extra bundles it generates! Would you still consider this improvement?

evbo avatar Mar 09 '22 19:03 evbo

@shadaj any words of wisdom how I could go about contributing a react Lazy support? Where in the code base might I refer to for how similar functionality is implemented? I'm not sure what your schedule is, but I don't think there's any other way to progressively load a slinky app other than enabling this feature so I might give it a try since I'm in desperate need!

Thanks for reopening :)

evbo avatar Mar 19 '22 22:03 evbo

@shadaj where I'm a bit stuck implementing a facade for lazy is that it requires the return of a module with default export, not simply a ReactElement. Using Scala.JS dynamicImport, do you have a hunch or any tips on how to signify that type? A module is just a file, so does it mean literally the bundled file path (a string?)?

evbo avatar May 10 '22 13:05 evbo

Okay, I think I have a working implementation of lazy that at least compiles. But I can't run it since scalajs-bundler doesn't yet support multiple outputs! @shadaj have you found a way around this?

Here's what I got so far:

trait LazyResult[P] extends js.Object {
  val default: FunctionalComponent[P]
}

@js.native
@JSImport("react", JSImport.Namespace, "React")
object ReactShim extends js.Object {
  final def `lazy`[P](f: js.Function0[js.Promise[LazyResult[P]]]): FunctionalComponent[P] = js.native
}

The only awkward bit is the props require you to explicitly instantiate the case class, but other than that it's not too ugly:

@react
object App {

  type Props = Unit

  val other = ReactShim.`lazy`(() => js.dynamicImport(new LazyResult[Other.Props]{
    override val default = Other.component
  }))

  val component = FunctionalComponent[Props] { props =>

    val (show, setShow) = useState[Boolean](false)

    div(
      "Hey!",
      button(onClick := (() => setShow(true))),
      if (show) {
        other(Other.Props("hello"))
      } else {
        Nil
      }
    )
  }
}

evbo avatar May 19 '22 13:05 evbo