Skip to content

Commit a734aa7

Browse files
committed
Add ModStateWithPropsFn
1 parent 1681f81 commit a734aa7

File tree

7 files changed

+86
-10
lines changed

7 files changed

+86
-10
lines changed

core/src/main/scala/japgolly/scalajs/react/SetStateFns.scala

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ package japgolly.scalajs.react
33
import scala.runtime.AbstractFunction2
44
import japgolly.scalajs.react.internal.identityFn
55

6-
final class SetStateFn[F[_], S](underlyingFn: (Option[S], Callback) => F[Unit]) extends AbstractFunction2[Option[S], Callback, F[Unit]] with StateAccess.SetState[F, S] {
6+
final class SetStateFn[F[_], S](underlyingFn: (Option[S], Callback) => F[Unit])
7+
extends AbstractFunction2[Option[S], Callback, F[Unit]] with StateAccess.SetState[F, S] {
78

89
override def apply(newState: Option[S], callback: Callback): F[Unit] =
910
underlyingFn(newState, callback)
@@ -29,7 +30,8 @@ object SetStateFn {
2930

3031
// =====================================================================================================================
3132

32-
final class ModStateFn[F[_], S](underlyingFn: (S => Option[S], Callback) => F[Unit]) extends AbstractFunction2[S => Option[S], Callback, F[Unit]] with StateAccess.ModState[F, S] {
33+
final class ModStateFn[F[_], S](underlyingFn: (S => Option[S], Callback) => F[Unit])
34+
extends AbstractFunction2[S => Option[S], Callback, F[Unit]] with StateAccess.ModState[F, S] {
3335

3436
override def apply(f: S => Option[S], callback: Callback): F[Unit] =
3537
underlyingFn(f, callback)
@@ -41,14 +43,53 @@ final class ModStateFn[F[_], S](underlyingFn: (S => Option[S], Callback) => F[Un
4143
override def toModStateFn: ModStateFn[F, S] =
4244
this
4345

46+
def toModStateWithPropsFn[P](p: P): ModStateWithPropsFn[F, P, S] =
47+
ModStateWithPropsFn((f, cb) => underlyingFn(f(_, p), cb))
48+
4449
def toSetStateFn: SetStateFn[F, S] =
4550
SetStateFn((s, cb) => underlyingFn(_ => s, cb))
4651

47-
def xmap[A](f: S => A)(g: A => S): ModStateFn[F, A] =
52+
def xmapState[A](f: S => A)(g: A => S): ModStateFn[F, A] =
4853
ModStateFn((m, cb) => underlyingFn(s => m(f(s)) map g, cb))
4954
}
5055

5156
object ModStateFn {
5257
def apply[F[_], S](f: (S => Option[S], Callback) => F[Unit]): ModStateFn[F, S] =
5358
new ModStateFn(f)
5459
}
60+
61+
// =====================================================================================================================
62+
63+
final class ModStateWithPropsFn[F[_], P, S](underlyingFn: ((S, P) => Option[S], Callback) => F[Unit])
64+
extends AbstractFunction2[(S, P) => Option[S], Callback, F[Unit]] with StateAccess.ModStateWithProps[F, P, S] {
65+
66+
override def apply(f: (S, P) => Option[S], callback: Callback): F[Unit] =
67+
underlyingFn(f, callback)
68+
69+
/** @param callback Executed regardless of whether state is changed. */
70+
override def modStateOption(f: (S, P) => Option[S], callback: Callback): F[Unit] =
71+
underlyingFn(f, callback)
72+
73+
override def toModStateWithPropsFn: ModStateWithPropsFn[F, P, S] =
74+
this
75+
76+
def toModStateFn: ModStateFn[F, S] =
77+
ModStateFn((f, cb) => underlyingFn((s, p) => f(s), cb))
78+
79+
def toSetStateFn: SetStateFn[F, S] =
80+
SetStateFn((s, cb) => underlyingFn((_, _) => s, cb))
81+
82+
def mapProps[A](f: P => A): ModStateWithPropsFn[F, A, S] =
83+
ModStateWithPropsFn((m, cb) => underlyingFn((s, p) => m(s, f(p)), cb))
84+
85+
def widenProps[A >: P]: ModStateWithPropsFn[F, A, S] =
86+
mapProps(identityFn)
87+
88+
def xmapState[A](f: S => A)(g: A => S): ModStateWithPropsFn[F, P, A] =
89+
ModStateWithPropsFn((m, cb) => underlyingFn((s, p) => m(f(s), p) map g, cb))
90+
}
91+
92+
object ModStateWithPropsFn {
93+
def apply[F[_], P, S](f: ((S, P) => Option[S], Callback) => F[Unit]): ModStateWithPropsFn[F, P, S] =
94+
new ModStateWithPropsFn(f)
95+
}

core/src/main/scala/japgolly/scalajs/react/StateAccess.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ object StateAccess {
9898

9999
/** @param callback Executed regardless of whether state is changed. */
100100
def modStateOption(mod: (S, P) => Option[S], callback: Callback): F[Unit]
101+
102+
def toModStateWithPropsFn: ModStateWithPropsFn[F, P, S] =
103+
ModStateWithPropsFn(modStateOption)
101104
}
102105

103106
// ===================================================================================================================

core/src/main/scala/japgolly/scalajs/react/package.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ package object react extends ReactEventTypes {
2020
type ModStateFnPure[S] = ModStateFn[CallbackTo, S]
2121
type ModStateFnImpure[S] = ModStateFn[Id, S]
2222

23+
type ModStateWithPropsFnPure[P, S] = ModStateWithPropsFn[CallbackTo, P, S]
24+
type ModStateWithPropsFnImpure[P, S] = ModStateWithPropsFn[Id, P, S]
25+
2326
val GenericComponent = component.Generic
2427
type GenericComponent[P, CT[-p, +u] <: CtorType[p, u], U] = GenericComponent.ComponentSimple[P, CT, U]
2528

doc/TYPES.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,16 +304,20 @@ Secondly, there are the following classes that
304304
* require a single function for construction
305305
* extend Scala functions
306306
* extend an appropriate `StateAccess` trait
307-
* are great to pass around components
307+
* allows call-site to choose the set/mod-state variation they need (eg. `setState(s)` vs `setState(Option(s), cb)`)
308308

309309
```scala
310310
SetStateFn[F, S]
311311
ModStateFn[F, S]
312+
ModStateWithPropsFn[F, P, S]
313+
312314
// And aliases:
313315
SetStateFnPure[S]
314316
SetStateFnImpure[S]
315317
ModStateFnPure[S]
316318
ModStateFnImpure[S]
319+
ModStateWithPropsFnPure[P, S]
320+
ModStateWithPropsFnImpure[P, S]
317321
```
318322

319323
# Events

doc/changelog/1.2.0.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,24 @@ and provided significant motivation (through my gratitude) to get through all th
7777
* `seamless`
7878
* `selected`
7979

80-
* There are now 2 new classes: `SetStateFn` and `ModStateFn` that you can use to pass around a single function that
80+
* Added new classes that you can use to pass around a single function that
8181
does `setState` or `modState` respectively, with downstream callers able to choose the variation they need.
82-
(Eg. `setState(s)` or `setState(Option(s), cb)`, etc
82+
(Eg. `setState(s)` or `setState(Option(s), cb)`)
83+
84+
```scala
85+
SetStateFn[F, S]
86+
ModStateFn[F, S]
87+
ModStateWithPropsFn[F, P, S]
88+
89+
// And aliases:
90+
SetStateFnPure[S]
91+
SetStateFnImpure[S]
92+
ModStateFnPure[S]
93+
ModStateFnImpure[S]
94+
ModStateWithPropsFnPure[P, S]
95+
ModStateWithPropsFnImpure[P, S]
96+
```
97+
8398

8499
* `StateAccessor` typeclasses now support all the `…{set,mod}State…` methods that `StateAccess` provides,
85100
including the optional `Callback` args and the new `{set,mod}StateOption` methods.

monocle-cats/src/main/scala/japgolly/scalajs/react/MonocleReact.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,13 @@ object MonocleReact extends MonocleExtComponent with MonocleExtStateSnapshot {
1414
}
1515

1616
implicit final class MonocleReactExt_ModStateFn[F[_], S](private val self: ModStateFn[F, S]) extends AnyVal {
17-
def xmapL[T](l: Iso[S, T]): ModStateFn[F, T] =
18-
self.xmap(l.get)(l.reverseGet)
17+
def xmapStateL[T](l: Iso[S, T]): ModStateFn[F, T] =
18+
self.xmapState(l.get)(l.reverseGet)
19+
}
20+
21+
implicit final class MonocleReactExt_ModStateWithPropsFn[F[_], P, S](private val self: ModStateWithPropsFn[F, P, S]) extends AnyVal {
22+
def xmapStateL[T](l: Iso[S, T]): ModStateWithPropsFn[F, P, T] =
23+
self.xmapState(l.get)(l.reverseGet)
1924
}
2025

2126
implicit final class MonocleReactExt_RouteCommon[R[X] <: RouteCommon[R, X], A](private val r: RouteCommon[R, A]) extends AnyVal {

monocle/src/main/scala/japgolly/scalajs/react/MonocleReact.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,13 @@ object MonocleReact extends MonocleExtComponent with MonocleExtStateSnapshot {
1414
}
1515

1616
implicit final class MonocleReactExt_ModStateFn[F[_], S](private val self: ModStateFn[F, S]) extends AnyVal {
17-
def xmapL[T](l: Iso[S, T]): ModStateFn[F, T] =
18-
self.xmap(l.get)(l.reverseGet)
17+
def xmapStateL[T](l: Iso[S, T]): ModStateFn[F, T] =
18+
self.xmapState(l.get)(l.reverseGet)
19+
}
20+
21+
implicit final class MonocleReactExt_ModStateWithPropsFn[F[_], P, S](private val self: ModStateWithPropsFn[F, P, S]) extends AnyVal {
22+
def xmapStateL[T](l: Iso[S, T]): ModStateWithPropsFn[F, P, T] =
23+
self.xmapState(l.get)(l.reverseGet)
1924
}
2025

2126
implicit final class MonocleReactExt_RouteCommon[R[X] <: RouteCommon[R, X], A](private val r: RouteCommon[R, A]) extends AnyVal {

0 commit comments

Comments
 (0)