Reputation: 113
My issue is also here: https://gist.github.com/somanythings/8c3d34de754af311d7826ea837d160b4
In using scalajs with japgolly's scalajs-react (https://github.com/japgolly/scalajs-react) library. I am trying to wrap the griddle grid http://griddlegriddle.github.io/Griddle/customization.html I want a custom column, and to do that requires I pass a columnMetadata structure which includes a component.
When I do, I can render a scalajs defined component that doesn't have properties, but if I try to access properties through renderP, or scope through renderS, they are both undefined in the scope of the render function. If I debug in the browser, they names are bound, and do have the expected values.
When I break on
def renderP(f: (DuringCallbackU[P, S, B], P) => ReactElement): Out =
render($ => f($, $.props))
then $.props
is undefined
What am I missing? Is it a simple typing issue in the ReactComponentB dispatching. Is it somehow related to https://github.com/japgolly/scalajs-react/issues/157, and I just haven't seen how?
// Confusion over how to pass a scalajs defined component to a javascript defined component
object GriddleComponentWrapper {
// for customComponent I've tried js.Any, ReactComponentU
@ScalaJSDefined
class ColumnMeta(val columnName: String, val order: Int, val customComponent: ReactClass=null) extends js.Object
}
case class GriddleComponentWrapper(results: js.Any, //Seq[Map[String, Any]],
columns: Seq[String],
columnMeta: Option[Seq[ColumnMeta]] = None,
showSettings: Boolean = true,
showFilter: Boolean = true
) {
def toJS = {
val p = js.Dynamic.literal()
p.updateDynamic("results")(results)
p.updateDynamic("columns")(columns)
p.updateDynamic("showSettings")(showSettings)
p.updateDynamic("showFilter")(showFilter)
(columnMeta).foreach { case cm => p.updateDynamic("columnMetadata")(cm.toJsArray) }
p
}
def apply(children: ReactNode*) = {
val f = React.asInstanceOf[js.Dynamic].createFactory(js.Dynamic.global.Bundle.griddle) // access real js component , make sure you wrap with createFactory (this is needed from 0.13 onwards)
f(toJS, children.toJsArray).asInstanceOf[ReactComponentU_]
}
}
object MyTestGrid {
@js.native
class ColumnMetaProps(val data: js.Object, val rowData: js.Object, val metadata: js.Object) extends js.Object
// I've tried making the Props argument js.Dynamic, and also the ColumnMetaProps above
@JSExport
val testComp = ReactComponentB[js.Dynamic]("Mine").renderP(
(sc, props: js.Dynamic) => {
//when debugging this in the browser, 'sc' and 'props' have inspectable object values with the expected members in the browser
//dev tools, BUT, they're undefined
log.info(s"what is ${sc.props}")
log.info(s"what is $props")
val string: Frag = if (!js.isUndefined(props)) props.data.toString() else "nothing!"
<.h1(string)
}).build
@JSExport
val aCompletelyStaticComponentWithNoPropsWillWork = ReactComponentB[js.Dynamic]("MyStaticComponent").renderP(
(sc, props: js.Dynamic) => <.h1("this renders!!") ).build
// am I passing the right thing to columnmeta with testComp.reactClass?
val columnMeta = (new ColumnMeta("c1", 1, testComp.reactClass) :: Nil).toJsArray
val results = Seq(
js.Dynamic.literal("c1" -> "row1c1", "c2" -> "row1c2"),
).toJsArray
val component = ReactComponentB[js.Dynamic]("MyTestGrid")
.render_P {
props =>
GriddleComponentWrapper(results, columns = "c1" :: "c2" :: Nil, columnMeta = Some(columnMeta))()
}.build
def apply() = component
}
Upvotes: 2
Views: 481
Reputation: 1330
React.JS requires that props and state always be an object (or null). Using a single Scala value like a primitive or case class instance, causes exceptions in React.JS. Therefore in scalajs-react, in order to allow users to use any props/state types in a type-safe manner, under the hood an object with a single key of "v"
is used. I.e. instead of using 123
directly, {v:123}
is used.
You likely will need to accommodate that boxing in your code.
Now, in the next major version (see the "neo" branch), the representations of components vastly improved such that there is no more hidden magic like I just described. Whereas v0.x wasn't designed to facilitate JS↔Scala component interop, it will be explicit, obvious, and hopefully trivial in neo.
Upvotes: 4