Lots of big, juicy, modernising changes here. Make sure you at least read the migration guide.
Contents:
- Major New Features
- Minor New Features
- Removals
- Changes: Backwards-Incompatible
- Changes: Backwards-Compatible
- Changes: Auto-Migratable
- Migration
- Changes in RCs
- Thanks
-
Scala 3 support
-
React Hooks (doc)
-
- Contexts now have optional displayNames.
You can optionally specify it on creation via
React.createContext(displayName, defaultValue)
. You can also read it via.displayName
. - Add
disableRemotePlayback
HTML attribute - Add
enterKeyHint
HTML attribute
- Contexts now have optional displayNames.
You can optionally specify it on creation via
-
Effect generalisation:
- You can now provide any kind of supported effect in place of just
Callback(To)
in many cases. Eg. you can now pass anAsyncCallback
to an event handler without converting it to aCallback
. - Additional effect types can be used by including the appropriate module; no imports required.
Eg. if you include the Cats Effect extension module you can pass an
IO
directly to scalajs-react. - The default effect types are now configurable. Default effect types are used when scalajs-react provides
you with effect values. Eg. calling
.props
fromBackendScope
used to be hardcoded to return aCallbackTo[Props]
becauseCallbackTo
used to be hardcoded as the default sync effect type.- If you use the
core
module then everything will be the same as it was withCallback(To)
andAsyncCallback
being the default sync and async effect types respectively. - If you use the new
core-bundle-cats_effect
module instead ofcore
, then Cats Effects'SyncIO
andIO
types will be the default sync and async effect types respectively.
- If you use the
- The
Callback(To)
,AsyncCallback
,CallbackOption
classes are now optional. If you use a different core bundle (eg.core-bundle-cats_effect
instead ofcore
) then classes likeCallbackTo
wont even be on the classpath unless you explicitly add thecallback
module. - If you're a scalajs-react library author, there's a guide just for you: Creating an Effect-Agnostic Library.
- You can now provide any kind of supported effect in place of just
-
Modularity. There are now many more modules (i.e. Maven artifacts) that are smaller and more pluggable, for increased flexibility. For example, the React Scala.JS facades now live in their own modules without any other scalajs-react specific functionality. (doc)
-
Global settings have been fixed and revamped. See the new guide here. This allows you to produce different dev and prod builds without making code changes.
-
Support turning React warnings into runtime exceptions. There are a few ways to do this:
- Via a new config option for
ReactTestUtils
- Manually
- Via a new config option for
-
Upgrade scala-js-dom to 2.0.0. This is mostly source-compatible with v1.2.0, but isn't binary-compatible. See the scala-js-dom v2 release notes.
-
Add support for Monocle v3
-
Add Router DSL to handle repeated query params like
?a=1&a=2
:queryToSeq
which gives you aSeq[(String, String)]
queryToMultimap
which gives you aMap[String, Seq[String]
-
Add to
object Callback
:def runAll(callbacks: CallbackTo[Any]*): Callback
-- Any exceptions get aprintStackTrace
and are then discarded, and the next callback run.
-
Add to
object CallbackTo
:def fromJsFn[A](f: js.Function0[A]): CallbackTo[A]
-
Add to
Callback{,To}
instances:def reset: Callback
-- If this completes successfully, discard the result. If any exception occurs, callprintStackTrace
and continue.
-
Add to
AsyncCallback
instances:def reset: AsyncCallback[Unit]
-- If this completes successfully, discard the result. If any exception occurs, callprintStackTrace
and continue.
-
Add to
object CallbackOption
:def suspend[A](f: => CallbackOption[A]): CallbackOption[A]
def traverse_
def sequence_
-
Add to
CallbackOption
instances:def finallyRun[B](runFinally: CallbackOption[B]): CallbackOption[A]
def when_(cond: => Boolean): CallbackOption[Unit]
def unless_(cond: => Boolean): CallbackOption[Unit]
-
New extension method
showDom(): String
available on mounted components givenimport japgolly.scalajs.react.test._
and/orimport japgolly.scalajs.react.test.ReactTestUtil._
-
Add
Reusable.emptyVdom
which has the typeReusable[TagMod]
-
Add to cats module:
- Implicit
MonadThrow
instances for scalajs-react effect types - Implicit
Monoid
instances for scalajs-react effect types with a monoidal value
- Implicit
- Dropped support for Scala 2.12
- Dropped support for Scala.JS 0.6.x
- Dropped Scalaz support. The following modules are no longer available:
ext-monocle
(deprecated version ofext-monocle-scalaz
)ext-monocle-scalaz
ext-scalaz72
- Removed state monad support (
ReactS
,ReactST
, etc) - Removed code deprecated in 1.5.x
- Removed
scala-collection-compat
as a dependency - Removed
CallbackKleisli
- Removed
.namespace
from VDOM tags - it's an ancient legacy artifact that is no longer used
-
scalajs-dom has been bumped to v2.0.0. This is backwards-incompatible with v1.x.y.
-
If you used to just add the
extra
module to your sbt'slibraryDependencies
and rely oncore
being included as a transitive dependency, it will no longer work. Explicitly add thecore
to yourlibraryDependencies
. -
In
ReactTestUtils
,act
andactAsync
now return the argument's value after it's executed -
RouterCtl#onLinkClick
now returns aOption[Callback]
instead of aCallbackOption[Unit]
. If necessary, wrap inCallbackOption.optionCallback
to convert back toCallbackOption[Unit]
, or.getOrEmpty
to turn into aCallback
. -
traverse
andsequence
methods inCallback
,CallbackTo
,AsyncCallback
,CallbackOption
now require anIterable
instead of anIterableOnce
-
Backwards-incompatible module changes:
Old Module Name New Module Name ext-cats
core-ext-cats
ext-cats-effect
core-ext-cats_effect
ext-monocle
Discontinued ext-monocle-cats
extra-ext-monocle2
ext-monocle-scalaz
Discontinued ext-scalaz72
Discontinued -
-Xelide-below
no longer used. There are a few runtime checks that scalajs-react performs in a few places (currently js component wrapping, router construction). Previously you could disable and remove these from your JS output by specifying-Xelide-below ASSERTION
as a scalac flag. Scala 3 doesn't support elision and it's too obscure a feature anyway so as of this version, scalajs-react runtime assertions will always appear in development mode (fastOptJS
) and will be removed in production mode (fullOptJS
). -
Upgraded the Cats Effect to v3
-
The SVG attribute
colorProfile
is nowcolorProfileAttr
-
ReactTestUtils
:render
methods now callact()
under the hoodwith*Render*
methods that take a(f: M => A)
can now also take(f: (Element, M) => A)
withParent(f: Element => A)
-
Reusability derivation now also includes a reference-equality check by default. If the reference-equality check fails, then it falls back to a content-based check.
-
VdomNode
instances now have arenderIntoDOM
method (just likeVdomElement
) -
Make covariant:
AsyncCallback
AsyncCallback.Forked
CallbackTo
CallbackOption
-
Additions
AsyncCallback.debounce(duration): AsyncCallback[Unit]
Callback.debounce(duration): Callback
ScalaFnComponent.withReuse{,By}
ScalaFnComponent.withChildrenAndReuse{,By}
- Add a
withFilter
method toCallback(To)
andAsyncCallback
- Add a
dispatch
method toCallback
andAsyncCallback
which schedules (-and-forgets) the callback to be run in the background TriStateCheckbox
now accepts an optionalReusable[TagMod]
in itsProps
that will be applied to the<input>
-
Bug fixes:
- ScalaFnComponents now use
VdomNode
s instead ofVdomElement
s - ForwardRefs now use
VdomNode
s instead ofVdomElement
s - Input to
AsyncCallback.traverse
et al should only be evaluated once per callback invocation - Input to
CallbackOption.traverse
et al should only be evaluated once per callback invocation
- ScalaFnComponents now use
-
Avoid boxing in
React.Context
andgetSnapshotBeforeUpdate
-
ReactTestUtils
is now atrait
as well as anobject
so that you can mix it into your own test utils collection -
Px[A]#extract
now takes an implicitPx.Extract[A](Px[A] => A)
argument instead of being a macro. If you're using this exotic feature, you can now provide your ownPx.Extract
typeclass instances. -
Backwards-compatible dependency upgrades:
- Cats to 2.6.1
- Cats Effect to 3.2.9
- Monocle (v2) to 2.1.0
- Monocle (v3) to 3.1.0
- Scala to 2.13.6
- Scala.js to 1.7.1
- Sourcecode to 0.2.7
You can run the script in the Migration section at the bottom of the page to automatically perform these changes.
-
If you use any of the Router DSL
.addCondition
methods and provide aPage => CallbackTo[Boolean]
, you'll now need to add aBy
suffix (eg.addConditionBy
). -
Renamed
CatsReact
⇒ReactCats
MonocleReact
⇒ReactMonocle
- In
ReactTestUtils
:withNewBodyElementAsync{Callback ⇒ }
withNewDocumentElementAsync{Callback ⇒ }
withRenderedAsync{Callback ⇒ }
withRenderedIntoBodyAsync{Callback ⇒ }
withRenderedIntoDocumentAsync{Callback ⇒ }
-
Renamed (with old names still in place but deprecated)
AsyncCallback.{byName ⇒ suspend}
Callback.{byName ⇒ suspend}
CallbackTo.{byName ⇒ suspend}
CallbackOption.{liftOption ⇒ option}
CallbackOption.{liftOptionCallback ⇒ optionCallback}
CallbackOption.{liftOptionLike ⇒ maybe}
CallbackOption.{liftOptionLikeCallback ⇒ maybeCallback}
CallbackOption.{liftValue ⇒ delay}
CallbackOption.liftCallback(callback) ⇒ callback.toCBO
CallbackOption(callback) ⇒ callback.asCBO
JsFnComponent.fromScala.{byName ⇒ delay}
Reusability.{byName ⇒ suspend}
-
Renamed any and all vdom method names from
`kebab-case`
tocamelCase
-
Make sure to read the Changes: Backwards-Incompatible section above.
-
Run this:
find . -type f -name '*.scala' -exec perl -pi -e ' s/\b(AsyncCallback[ .]+)byName\b/\1suspend/g; s/\b(Callback[ .]+)byName\b/\1suspend/g; s/\b(CallbackTo[ .]+)byName\b/\1suspend/g; s/\b(CallbackOption[ .]+)liftOption\b/\1option/g; s/\b(CallbackOption[ .]+)liftOptionCallback\b/\1optionCallback/g; s/\b(CallbackOption[ .]+)liftOptionLike\b/\1maybe/g; s/\b(CallbackOption[ .]+)liftOptionLikeCallback\b/\1maybeCallback/g; s/\b(CallbackOption[ .]+)liftValue\b/\1delay/g; s/\bCallbackOption *\( *([a-zA-Z_](?:[a-zA-Z0-9_. ]*[a-zA-Z0-9_])?) *\)/\1.asCBO/g; s/\bCallbackOption[ .]+liftCallback *\( *([a-zA-Z_](?:[a-zA-Z0-9_. ]*[a-zA-Z0-9_])?) *\)/\1.toCBO/g; s/\b(JsFnComponent[ .]+fromScala[ .]+)byName\b/\1delay/g; s/\b(Reusability[ .]+)byName\b/\1suspend/g; s/\bMonocleReact\b/ReactMonocle/g; s/\bCatsReact\b/ReactCats/g; s/\b(withNewBodyElementAsync)Callback\b/\1/g; s/\b(withNewDocumentElementAsync)Callback\b/\1/g; s/\b(withRenderedAsync)Callback\b/\1/g; s/\b(withRenderedIntoBodyAsync)Callback\b/\1/g; s/\b(withRenderedIntoDocumentAsync)Callback\b/\1/g; s/\bnew OnUnmount.Backend\b/OnUnmount()/g; s/\b(addCondition(?:With(?:Optional)?Fallback)?)( *\( *[a-zA-Z_][a-zA-Z0-9_]* +=>)/\1By\2/g; s/Reusability\.byRef +\|\| +(Reusability\.(?:derive|caseClassExcept))/\1/g; s/`all-scroll`/allScroll/g; s/`bidi-override`/bidiOverride/g; s/`border-box`/borderBox/g; s/`break-all`/breakAll/g; s/`break-word`/breakWord/g; s/`cjk-decimal`/cjkDecimal/g; s/`col-resize`/colResize/g; s/`color-profile`/colorProfile/g; s/`content-box`/contentBox/g; s/`context-menu`/contextMenu/g; s/`decimal-leading-zero`/decimalLeadingZero/g; s/`e-resize`/eResize/g; s/`ew-resize`/ewResize/g; s/`font-face-format`/fontFaceFormat/g; s/`font-face-name`/fontFaceName/g; s/`font-face-src`/fontFaceSrc/g; s/`font-face-uri`/fontFaceUri/g; s/`font-face`/fontFace/g; s/`hiragana-iroha`/hiraganaIroha/g; s/`inline-block`/inlineBlock/g; s/`inline-flex`/inlineFlex/g; s/`inline-table`/inlineTable/g; s/`katakana-iroha`/katakanaIroha/g; s/`keep-all`/keepAll/g; s/`line-through`/lineThrough/g; s/`list-item`/listItem/g; s/`lower-alpha`/lowerAlpha/g; s/`lower-greek`/lowerGreek/g; s/`lower-latin`/lowerLatin/g; s/`lower-roman`/lowerRoman/g; s/`missing-glyph`/missingGlyph/g; s/`n-resize`/nResize/g; s/`ne-resize`/neResize/g; s/`nesw-resize`/neswResize/g; s/`no-drop`/noDrop/g; s/`not-allowed`/notAllowed/g; s/`ns-resize`/nsResize/g; s/`nw-resize`/nwResize/g; s/`nwse-resize`/nwseResize/g; s/`padding-box`/paddingBox/g; s/`pre-line`/preLine/g; s/`pre-wrap`/preWrap/g; s/`preserve-3d`/preserve3d/g; s/`row-resize`/rowResize/g; s/`s-resize`/sResize/g; s/`se-resize`/seResize/g; s/`sw-resize`/swResize/g; s/`table-caption`/tableCaption/g; s/`table-cell`/tableCell/g; s/`table-column-group`/tableColumnGroup/g; s/`table-column`/tableColumn/g; s/`table-footer-group`/tableFooterGroup/g; s/`table-header-group`/tableHeaderGroup/g; s/`table-row-group`/tableRowGroup/g; s/`table-row`/tableRow/g; s/`text-bottom`/textBottom/g; s/`text-top`/textTop/g; s/`under left`/underLeft/g; s/`under right`/underRight/g; s/`upper-alpha`/upperAlpha/g; s/`upper-latin`/upperLatin/g; s/`upper-roman`/upperRoman/g; s/`vertical-text`/verticalText/g; s/`w-resize`/wResize/g; s/`x-large`/xLarge/g; s/`x-small`/xSmall/g; s/`xx-large`/xxLarge/g; s/`xx-small`/xxSmall/g; s/`zoom-in`/zoomIn/g; s/`zoom-out`/zoomOut/g; ' {} +
If you're interested in the changes between each RC release, see here.
A lot of this was kindly sponsored by Gemini/NOIRLab/AURA. Huge thanks to @cquiroz for making this possible, and to @rpiaggio for the awesome ideas that helped guide design.
We all want features like Scala 3 support but in reality it's a ton of work to implement. It's not very feasible for an OSS maintainer to do literally months of full-time work for free. On behalf of myself and the scalajs-react community, thank you so much for sponsoring this huge effort!