slinky
slinky copied to clipboard
React 16.6 feature support
- [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)
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).
The remaining two features are generally pretty incompatible with Scala (typing) / Scala.js (dynamic imports), so going to close this issue for now.
@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?
@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 :)
@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?)?
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
}
)
}
}