Skip to content

Commit ad2f03f

Browse files
committed
Describe #145 and Callback in CHANGELOG
1 parent ea8329d commit ad2f03f

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed

doc/CHANGELOG-0.10.md

+109
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,118 @@
88
please copy Router v1 into your own codebase.
99
Maintaining two Routers in scalajs-react is not good.
1010

11+
* [#145](https://github.com/japgolly/scalajs-react/issues/145): Unify `-->` `==>` `~~>`, remove Scalaz `IO`, add `Callback`.
12+
13+
**Problem:**<br>
14+
A gap in the community and library was growing because there were two separate ways of writing callbacks.
15+
An example of which, numerous users using the built-in `Router` experienced confusion and were forced to
16+
discover Scalaz's (and Haskell's) `unsafePerformIO()` without understanding the reasons or benefit.
17+
Another example, writing mixins or shared libraries, one would have to create duplicate methods with differing
18+
type signatures in order to accomodate both styles.
19+
More examples exist, but it should be clear that this please-everyone approach has failed.
20+
21+
**Solution:**<br>
22+
A new data type `Callback` has been added
23+
(which is actually an alias to the real type `CallbackTo[A]` where `Callback = CallbackTo[Unit]`).
24+
It replaces the existing two competing methods of `() => Unit` and Scalaz `IO[Unit]`.
25+
A basic rule of thumb is if a function performs an effect (changing DOM, using network, changing React state),
26+
it should be wrapped in a `Callback`.
27+
28+
* When creating HTML, `-->` and `==>` only accept `Callback`s.
29+
* `setState()`, `modState()` etc now return `Callback`s.
30+
* Core now has `_setState()`, `_modState()`.
31+
* Component lifecycle methods (like `componentWillMount`) now accept `Callback`.
32+
* `Router` no longer uses Scalaz `IO`.
33+
* Mixins in `extra` no longer have duplicate methods for Scalaz `IO`.
34+
35+
For Scalaz users:<br>
36+
Either use `CallbackTo` instead of `IO`, or else change your `IO`s to `CallbackTo`s when you pass them to React.
37+
* `~~>` is removed. Use `-->` and `==>` instead.
38+
* `{,_}{set,mod}StateIO` methods all removed and in core without the `IO`.
39+
* Isomorphism between `IO` and `CallbackTo` with convenience extension methods `.toCallback` and `.toIO`.
40+
* `OpCallbackIO` has been removed in favour of plain `Callback`.
41+
* New state-monad type-inference convenience: `FixCB[S] = FixT[CallbackTo, S]`
42+
43+
**Example migrations**<br>
44+
45+
Example #1
46+
```scala
47+
// Before
48+
val Example = ReactComponentB[Unit]("Example")
49+
.initialState(0)
50+
.render { $ =>
51+
52+
def clickHandler = $.modState(_ + 1)
53+
<.div(
54+
<.div("Button pressed ", $.state, " times."),
55+
<.button("CLICK ME", ^.onClick --> clickHandler))
56+
57+
}.buildU
58+
59+
// After
60+
// Surprise! No change needed.
61+
// modState() now returns a Callback which is exactly what --> expects.
62+
```
63+
64+
Example #2<br>
65+
```scala
66+
// Before (excerpt from example above)
67+
def clickHandler: Unit = {
68+
println("Updating state.")
69+
$.modState(_ + 1)
70+
}
71+
72+
// Callbacks can compose in many different ways.
73+
// The following examples all do the same thing in the same order.
74+
75+
// Method #1: >>
76+
def clickHandler: Callback =
77+
Callback(println("Updating state.")) >>
78+
$.modState(_ + 1)
79+
80+
// Method #2: precedeWith
81+
def clickHandler: Callback =
82+
$.modState(_ + 1).precedeWith {
83+
println("Updating state.")
84+
}
85+
86+
// After, Method #3: <<
87+
def clickHandler: Callback =
88+
$.modState(_ + 1) << Callback(println("Updating state."))
89+
90+
// After, Method #4: runNow()
91+
def clickHandler = Callback {
92+
println("Updating state.")
93+
$.modState(_ + 1).runNow()
94+
}
95+
```
96+
97+
Example #3: Snippet from https://japgolly.github.io/scalajs-react/#examples/todo<br>
98+
```scala
99+
// Before
100+
def handleSubmit(e: ReactEventI) = {
101+
e.preventDefault()
102+
$.modState(s => State(s.items :+ s.text, ""))
103+
}
104+
105+
// After
106+
def handleSubmit(e: ReactEventI) =
107+
e.preventDefaultCB >>
108+
$.modState(s => State(s.items :+ s.text, ""))
109+
```
110+
111+
11112
<br>
12113
Migration commands:
13114
```sh
14115
# extra.{router2 ⇒ router}
15116
find . -name '*.scala' -type f -exec perl -pi -e 's/(?<=extra\.router)2//g' {} +
117+
118+
# Unfortunately the migration to Callback is mostly manual.
119+
# Here are some commands I used to help but they'll only get you halfway there.
120+
find . -name '*.scala' -type f -exec perl -pi -e 's/(?<=forceUpdate)\(\)//g' {} +
121+
find . -name '*.scala' -type f -exec perl -pi -e 's/(?<=tryFocus)\(\)//g' {} +
122+
find . -name '*.scala' -type f -exec perl -pi -e 's/(?<=(set|mod)State)IO//g' {} +
123+
find . -name '*.scala' -type f -exec perl -pi -e 's/FixT\[IO *, */FixCB[/' {} +
124+
find . -name '*.scala' -type f -exec perl -pi -e 's/ReactST\[IO *,/ReactST[CallbackTo,/' {} +
16125
```

0 commit comments

Comments
 (0)