Types
March 12, 2018 · View on GitHub
You barely need to know any of these in order to use scalajs-react. This is here as an optional reference.
Components
Type parameters below are abbreviated as follows:
P= PropsCT=CtorTypeU= UnmountedM= MountedF= Effect type
Stages
React components can be thought of as having 3 stages.
Component- A component at it's top-level. After creation, before use. Input (props and/or children) may be required. Pure.Unmounted- An instance of a component that's ready to be rendered. Still pure at this point.Mounted- A reference to a component that has been mounted/rendered. Usually live. Impure as it can change as the user interacts with the app. Pure versions available where impurity is encapulated inCallbackTo[A].
Example:
// Stage 1: Component
val component = ScalaComponent.builder[String]("HelloComponent")
.render(i => <.div(s"Hello ${i.props}. How are you?"))
.build
// Stage 2: Unmounted
val unmounted = component("David")
// Stage 3: Mounted
val mounted = unmounted.renderIntoDOM(...)
Behaviour
Some types declare behaviour.
Children
You are required to specify one of these when creating a JS component.
Children.None- indicates that a component doesn't use.props.children.Children.Varargs- indicates that a component uses.props.childrenand accepts 0-n args.
(In future it may be useful to add Children.ExactlyOne as well.)
CtorType
The type of constructor that a component has. You only need to specify these when you want to explicitly declare the types of your components.
CtorType.Props- Props required. Construct likecomponent(props).CtorType.PropsAndChildren- Props and children required. Construct likecomponent(props)(children*).CtorType.Children- Children required. Construct likecomponent(children*).CtorType.Nullary- Nothing required. Construct likecomponent().
Generic
-
Generic representation of components. All components are subtypes of these. Useful in library methods that do something with any kind of component.
GenericComponent[P, CT, U] GenericComponent.Unmounted[P, M] GenericComponent.Mounted[F, P, S] GenericComponent.MountedPure[P, S] GenericComponent.MountedImpure[P, S] -
_Raw- Access to raw (i.e. JS-world / non-Scala.JS) values. Notice there are no type parameters. All components are subtypes of these. Useful for simple interop that doesn't care about the type of props/state.GenericComponent.ComponentRaw GenericComponent.UnmountedRaw GenericComponent.MountedRaw
JS components
-
JS components. Useful if you want to explicitly declare your component's types.
JsComponent[P, S, CT] JsComponent.Unmounted[P, S] JsComponent.Mounted[P, S] -
_WithFacade- Variations that accept a facade to the type once it's mounted. Useful if you want to explicitly declare your component's types.JsComponentWithFacade[P, S, Facade, CT] JsComponent.UnmountedWithFacade[P, S, Facade] JsComponent.MountedWithFacade[P, S, Facade] -
_Simple- They allow you to reference JS components more generically and with less constraints. Useful in library methods that do something with any kind of JS component, regardless of whether it's been mapped or modified after creation.JsComponent.ComponentSimple[P, CT, U] JsComponent.UnmountedSimple[P, M] JsComponent.MountedSimple[F, P, S, R] -
Raw types. I don't imagine library users would need to use this but just in case, there is also:
JsComponent.RawMounted[P, S] // the type of the raw JS mounted value without additional facades.
JsComponent.ComponentWithRawType[P, S, R, CT]
JsComponent.UnmountedWithRawType[P, S, R]
JsComponent.MountedWithRawType[P, S, R]
JS functional components
-
Main types. Useful if you want to explicitly declare your component's types.
JsFnComponent[P, CT] JsFnComponent.Unmounted[P] JsFnComponent.Mounted -
_Simple- They allow you to reference JS functional components more generically and with less constraints. Useful in library methods that do something with any kind of JS functional component, regardless of whether it's been mapped or modified after creation.JsFnComponent.ComponentSimple[P, CT, U] JsFnComponent.UnmountedSimple[P, M]
Scala components
The type parameter B below, is the type of the Scala component's backend.
- Main types:
ScalaComponent[P, S, B, CT]
ScalaComponent.Unmounted[P, S, B]
ScalaComponent.Mounted[F, P, S, B]
ScalaComponent.MountedImpure[P, S, B]
ScalaComponent.MountedPure[P, S, B]
BackendScope[P, S]
-
ScalaComponentConfig[P, Children, S, B]- When creating reusable component features (like mixins), use this as the return type. The feature is then applied by calling.configure(feature)when creating a Scala component. Example:object OnUnmount { def install[P, C <: Children, S, B <: OnUnmount]: ScalaComponentConfig[P, C, S, B] = _.componentWillUnmount(_.backend.unmount) } -
JS types. Useful if you want to deconstruct Scala components into their underlying JS representations.
ScalaComponent.JsComponent[P, S, B, CT] ScalaComponent.JsUnmounted[P, S, B] ScalaComponent.JsMounted[P, S, B] ScalaComponent.RawMounted[P, S, B] // the type of the raw JS mounted value ScalaComponent.Vars[P, S, B] // the JS facade over the raw JS mounted value
Scala functional components
-
Main types. Useful if you want to explicitly declare your component's types.
ScalaFnComponent[P, CT] ScalaFnComponent.Unmounted[P] ScalaFnComponent.Mounted
Roots
For all component types, whether they be generic, JS, Scala; functional or standard; each type parameter
(i.e. the props, the state, the result of mounting, etc.) can be changed.
In order to preserve transparency and lineage, the root/original/base component is never forgotten and always accessible by calling .root.
You'll likely never use or care about these types unless you're doing library interop. But if you need them, they're there, and they are as follows:
_Root- this is the type before any mapping or modification occurs. The original, underlying type.
GenericComponent.ComponentRoot[P, CT, U]
GenericComponent.UnmountedRoot[P, M]
GenericComponent.MountedRoot[F, P, S]
JsComponent.ComponentRoot[P, CT, U]
JsComponent.UnmountedRoot[P, M]
JsComponent.MountedRoot[F, P, S, R]
JsFnComponent.ComponentRoot[P, CT, U]
JsFnComponent.UnmountedRoot[P]
ScalaComponent.MountedRoot[F, P, S, B]
_WithRoot- this the type that is possibly mapped/modified, and contains a.rootmethod to the_Roottype.
GenericComponent.ComponentWithRoot[…]
GenericComponent.UnmountedWithRoot[…]
GenericComponent.MountedWithRoot[…]
JsComponent.ComponentWithRoot[…]
JsComponent.UnmountedWithRoot[…]
JsComponent.MountedWithRoot[…]
JsFnComponent.ComponentWithRoot[…]
JsFnComponent.UnmountedWithRoot[…]
ScalaComponent.MountedWithRoot[…]
State
There are a number of abstraction over state functionality constituents.
In the following types F is the effect type which is nearly always
CallbackTo for pure code, and Id where type Id[A] = A for impure usage.
StateAccess
Read- and write- access to mutable state.
All mounted components extend this.
Useful for passing around R/W access to one component's state (or state subset), to a child component.
Lifecycle scopes (eg. componentDidUpdate) do not extend this as in some cases, .state would be ambiguous.
StateAccess[F, S]
StateAccessPure[S]
StateAccessImpure[S]
StateAccessor
Typeclass for pure and/or impure, read- and/or write-access to mutable state.
Useful in library methods that do something with mutable state.
Unless StateAccess, lifecycle scopes (eg. componentDidUpdate) are supported via this method.
See extra/StateSnapshot.scala for an example.
StateAccessor.Read[I, F, S]
StateAccessor.ReadPure[I, S]
StateAccessor.ReadImpure[I, S]
StateAccessor.Write[I, F, S]
StateAccessor.WritePure[I, S]
StateAccessor.WriteImpure[I, S]
StateAccessor.ReadWrite[I, F, F, S]
StateAccessor.ReadWritePure[I, S]
StateAccessor.ReadWriteImpure[I, S]
StateAccessor.ReadImpureWritePure[I, S]
StateAccessor.ReadPureWriteImpure[I, S]
{Set,Mod}State abstractions
Firstly, StateAccess extends the following subtypes which can be used in isolation:
StateAccess.SetState[F, S]
StateAccess.ModState[F, S]
StateAccess.ModStateWithProps[F, P, S]
StateAccess.Write[F, S] // SetState & ModState
StateAccess.WriteWithProps[F, P, S] // Write & ModStateWithProps
Secondly, there are the following classes that
- require a single function for construction
- extend Scala functions
- extend an appropriate
StateAccesstrait - allows call-site to choose the set/mod-state variation they need (eg.
setState(s)vssetState(Option(s), cb))
SetStateFn[F, S]
ModStateFn[F, S]
ModStateWithPropsFn[F, P, S]
// And aliases:
SetStateFnPure[S]
SetStateFnImpure[S]
ModStateFnPure[S]
ModStateFnImpure[S]
ModStateWithPropsFnPure[P, S]
ModStateWithPropsFnImpure[P, S]
Events
The synthetic event types you read about in the React docs are typed as shown below.
The Node type param refers to the type of target DOM.
| React Event Type | Alias without typing the target |
|---|---|
ReactEventFrom[Node] | ReactEvent |
ReactClipboardEventFrom[Node] | ReactClipboardEvent |
ReactCompositionEventFrom[Node] | ReactCompositionEvent |
ReactDragEventFrom[Node] | ReactDragEvent |
ReactFocusEventFrom[Node] | ReactFocusEvent |
ReactKeyboardEventFrom[Node] | ReactKeyboardEvent |
ReactMouseEventFrom[Node] | ReactMouseEvent |
ReactTouchEventFrom[Node] | ReactTouchEvent |
ReactUIEvent[Node] | ReactUIEvent |
ReactWheelEventFrom[Node] | ReactWheelEvent |
You can also append one of these suffixes for convenience:
| Suffix | Node |
|---|---|
FromHtml | HTMLElement |
FromInput | HTMLInputElement |
FromTextArea | HTMLTextAreaElement |
For example, ReactDragEventFromInput is a ReactDragEvent over a HTMLInputElement (an <input>), the same as writing ReactDragEventFrom[HTMLInputElement].
Additionally there's object ReactMouseEvent which contains a utility for determining if a mouse event
on a link should open in a new tab.
VDOM
VDOM types are described here.