Skip to content

Commit

Permalink
Make redux container take props (#35)
Browse files Browse the repository at this point in the history
* Pass Props[OwnProps] for Redux containers

* Separate router container and presentation components in example

* v0.14.0
  • Loading branch information
shogowada authored May 9, 2017
1 parent c15f425 commit e656516
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 36 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ ReactDOM.render(<.div(^.id := "hello-world")("Hello, World!"), mountNode)
2. Depend on the libraries.
```
libraryDependencies ++= Seq(
"io.github.shogowada" %%% "scalajs-reactjs" % "0.13.1", // For react facade
"io.github.shogowada" %%% "scalajs-reactjs-router-dom" % "0.13.1", // Optional. For react-router-dom facade
"io.github.shogowada" %%% "scalajs-reactjs-router-redux" % "0.13.1", // Optional. For react-router-redux facade
"io.github.shogowada" %%% "scalajs-reactjs-redux" % "0.13.1", // Optional. For react-redux facade
"io.github.shogowada" %%% "scalajs-reactjs-redux-devtools" % "0.13.1" // Optional. For redux-devtools facade
"io.github.shogowada" %%% "scalajs-reactjs" % "0.14.0", // For react facade
"io.github.shogowada" %%% "scalajs-reactjs-router-dom" % "0.14.0", // Optional. For react-router-dom facade
"io.github.shogowada" %%% "scalajs-reactjs-router-redux" % "0.14.0", // Optional. For react-router-redux facade
"io.github.shogowada" %%% "scalajs-reactjs-redux" % "0.14.0", // Optional. For react-redux facade
"io.github.shogowada" %%% "scalajs-reactjs-redux-devtools" % "0.14.0" // Optional. For redux-devtools facade
)
```

Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ publishArtifact := false
val commonSettings = Seq(
organization := "io.github.shogowada",
name := "scalajs-reactjs",
version := "0.13.1",
version := "0.14.0",
licenses := Seq("MIT" -> url("https://opensource.org/licenses/MIT")),
homepage := Some(url("https://github.com/shogowada/scalajs-reactjs")),
scalaVersion := "2.12.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.github.shogowada.scalajs.reactjs.example.redux.devtools

import io.github.shogowada.scalajs.reactjs.React.Props
import io.github.shogowada.scalajs.reactjs.VirtualDOM._
import io.github.shogowada.scalajs.reactjs.classes.ReactClass
import io.github.shogowada.scalajs.reactjs.events.FormSyntheticEvent
Expand Down Expand Up @@ -49,7 +50,7 @@ object TextContainerComponent {
def apply(): ReactClass = ReactRedux.connectAdvanced(
(dispatch: Dispatch) => {
val onTextChange = (text: String) => dispatch(SetText(text))
(state: State, ownProps: Unit) => {
(state: State, ownProps: Props[Unit]) => {
WrappedProps(
text = state.text,
onTextChange = onTextChange
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.github.shogowada.scalajs.reactjs.example.redux.middleware

import io.github.shogowada.scalajs.reactjs.React.Props
import io.github.shogowada.scalajs.reactjs.VirtualDOM._
import io.github.shogowada.scalajs.reactjs.events.FormSyntheticEvent
import io.github.shogowada.scalajs.reactjs.redux.ReactRedux._
Expand Down Expand Up @@ -139,7 +140,7 @@ object Example {
val onAddFuture = (value: Int) => dispatch(Future(Add(value)))
val onAddFutureFailure = (value: Int) => dispatch(Future.failed(new Exception("This is a test. Do not panic.")))
val onSubtract = (value: Int) => dispatch(Subtract(value))
(state: State, ownProps: Unit) => {
(state: State, ownProps: Props[Unit]) => {
ExamplePresentational.WrappedProps(
result = state.result,
snapshot = state.snapshot,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package io.github.shogowada.scalajs.reactjs.example.router.redux

import io.github.shogowada.scalajs.history.History
import io.github.shogowada.scalajs.reactjs.React.Props
import io.github.shogowada.scalajs.reactjs.VirtualDOM._
import io.github.shogowada.scalajs.reactjs.events.{FormSyntheticEvent, SyntheticEvent}
import io.github.shogowada.scalajs.reactjs.events.FormSyntheticEvent
import io.github.shogowada.scalajs.reactjs.redux.ReactRedux._
import io.github.shogowada.scalajs.reactjs.redux.Redux.Dispatch
import io.github.shogowada.scalajs.reactjs.redux.devtools.ReduxDevTools
Expand Down Expand Up @@ -111,52 +112,69 @@ object Main extends JSApp {
}
}

object RouteControllerComponent {
/*
* Extend RouterProps to access router props (e.g. props.location, props.history, and props.match)
* */
object RouteControllerComponent extends RouterProps {

lazy val reactClass = ReactRedux.connectAdvanced(
(dispatch: Dispatch) => {
val act = (action: NativeAction) => dispatch(action)
(state: State, ownProps: Unit) => {
RouteControllerPresentationalComponent.WrappedProps(act)
val pushRouteA = () => dispatch(Push("/a"))
val pushRouteB = () => dispatch(Push("/b"))
val goNegative3 = () => dispatch(Go(-1))
val goBack = () => dispatch(GoBack())
val goForward = () => dispatch(GoForward())
(state: State, ownProps: Props[Unit]) => {
RouteControllerPresentationalComponent.WrappedProps(
path = ownProps.location.pathname,
onPushRouteAClick = pushRouteA,
onPushRouteBClick = pushRouteB,
onGoNegative3Click = goNegative3,
onGoBackClick = goBack,
onGoForwardClick = goForward
)
}
}
)(RouteControllerPresentationalComponent.reactClass)
}

object RouteControllerPresentationalComponent extends RouterProps {
case class WrappedProps(act: (NativeAction) => _)
object RouteControllerPresentationalComponent {
case class WrappedProps(
path: String,
onPushRouteAClick: () => _,
onPushRouteBClick: () => _,
onGoNegative3Click: () => _,
onGoBackClick: () => _,
onGoForwardClick: () => _
)

type Self = React.Self[WrappedProps, Unit]

lazy val reactClass = React.createClass[WrappedProps, Unit](
(self) =>
<.div()(
<.h3()("Path: ", <.span(^.id := "path")(self.props.location.pathname)),
<.h3()("Path: ", <.span(^.id := "path")(self.props.wrapped.path)),
<.div()(
<.button(^.id := "push-route-a", ^.onClick := act(self, Push("/a")))("Push route A"),
<.button(^.id := "push-route-b", ^.onClick := act(self, Push("/b")))("Push route B"),
<.button(^.id := "go-negative-3", ^.onClick := act(self, Go(-3)))("Go -3"),
<.button(^.id := "go-back", ^.onClick := act(self, GoBack()))("Go back"),
<.button(^.id := "go-forward", ^.onClick := act(self, GoForward()))("Go forward")
<.button(^.id := "push-route-a", ^.onClick := self.props.wrapped.onPushRouteAClick)("Push route A"),
<.button(^.id := "push-route-b", ^.onClick := self.props.wrapped.onPushRouteBClick)("Push route B"),
<.button(^.id := "go-negative-3", ^.onClick := self.props.wrapped.onGoNegative3Click)("Go -3"),
<.button(^.id := "go-back", ^.onClick := self.props.wrapped.onGoBackClick)("Go back"),
<.button(^.id := "go-forward", ^.onClick := self.props.wrapped.onGoForwardClick)("Go forward")
),
<.Switch()(
<.Route(^.path := "/a", ^.component := ARouteComponent.reactClass)(),
<.Route(^.path := "/b", ^.component := BRouteComponent.reactClass)()
)
)
)

private def act(self: Self, action: NativeAction) =
(event: SyntheticEvent) => {
event.preventDefault()
self.props.wrapped.act(action)
}
}

object ARouteComponent {
lazy val reactClass = ReactRedux.connectAdvanced(
(dispatch: Dispatch) => {
val onTextChange = (text: String) => dispatch(ChangeTextA(text))
(state: State, ownProps: Unit) => {
(state: State, ownProps: Props[Unit]) => {
RoutePresentationalComponent.WrappedProps(
text = state.wrapped.textA,
onTextChange = onTextChange
Expand All @@ -170,7 +188,7 @@ object BRouteComponent {
lazy val reactClass = ReactRedux.connectAdvanced(
(dispatch: Dispatch) => {
val onTextChange = (text: String) => dispatch(ChangeTextB(text))
(state: State, ownProps: Unit) => {
(state: State, ownProps: Props[Unit]) => {
RoutePresentationalComponent.WrappedProps(
text = state.wrapped.textB,
onTextChange = onTextChange
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.github.shogowada.scalajs.reactjs.example.todoappredux

import io.github.shogowada.scalajs.reactjs.React.Props
import io.github.shogowada.scalajs.reactjs.classes.ReactClass
import io.github.shogowada.scalajs.reactjs.redux.ReactRedux
import io.github.shogowada.scalajs.reactjs.redux.Redux.Dispatch
Expand All @@ -24,8 +25,8 @@ object ContainerComponents {
var ownProps: LinkContainerComponentOwnProps = null
val onClick: () => Unit = () => dispatch(SetVisibilityFilter(filter = ownProps.filter))

(state: State, nextOwnProps: LinkContainerComponentOwnProps) => {
ownProps = nextOwnProps
(state: State, nextOwnProps: Props[LinkContainerComponentOwnProps]) => {
ownProps = nextOwnProps.wrapped
Link.WrappedProps(
active = ownProps.filter == state.visibilityFilter,
onClick = onClick
Expand All @@ -37,7 +38,7 @@ object ContainerComponents {
def TodoListContainerComponent: ReactClass = ReactRedux.connectAdvanced(
(dispatch: Dispatch) => {
val onTodoClick: (Int) => Unit = (id: Int) => dispatch(ToggleTodo(id = id))
(state: State, ownProps: Unit) => {
(state: State, ownProps: Props[Unit]) => {
TodoList.WrappedProps(
todos = state.visibilityFilter match {
case VisibilityFilters.ShowAll => state.todos
Expand All @@ -53,7 +54,7 @@ object ContainerComponents {
def AddTodoContainerComponent: ReactClass = ReactRedux.connectAdvanced(
(dispatch: Dispatch) => {
val onAddTodo: (String) => Unit = (text: String) => dispatch(AddTodo(text = text))
(state: State, ownProps: Unit) =>
(state: State, ownProps: Props[Unit]) =>
AddTodoComponent.WrappedProps(
onAddTodo = onAddTodo
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ object ReactRedux {
}

def connectAdvanced[ReduxState, OwnProps, WrappedProps](
selectorFactory: Dispatch => (ReduxState, OwnProps) => WrappedProps
selectorFactory: Dispatch => (ReduxState, Props[OwnProps]) => WrappedProps
): ContainerComponentFactory[WrappedProps] = {
val nativeSelectorFactory = selectorFactoryToNative(selectorFactory)

Expand All @@ -40,7 +40,7 @@ object ReactRedux {
}

private def selectorFactoryToNative[ReduxState, OwnProps, WrappedProps](
selectorFactory: Dispatch => (ReduxState, OwnProps) => WrappedProps
selectorFactory: Dispatch => (ReduxState, Props[OwnProps]) => WrappedProps
): js.Function1[NativeDispatch, js.Function2[ReduxState, js.Dynamic, js.Any]] =
(nativeDispatch: NativeDispatch) => {
val dispatch: Dispatch = ReduxInternal.dispatchFromNative(nativeDispatch)
Expand All @@ -49,10 +49,10 @@ object ReactRedux {
}

private def selectorToNative[ReduxState, OwnProps, WrappedProps](
selector: (ReduxState, OwnProps) => WrappedProps
selector: (ReduxState, Props[OwnProps]) => WrappedProps
): js.Function2[ReduxState, js.Dynamic, js.Any] =
(state: ReduxState, nativeOwnProps: js.Dynamic) => {
val ownProps: OwnProps = Props(nativeOwnProps).wrapped
val ownProps: Props[OwnProps] = Props(nativeOwnProps)
val wrappedProps: WrappedProps = selector(state, ownProps)
val nativeProps = clone(nativeOwnProps)
nativeProps.updateDynamic(React.WrappedProperty)(wrappedProps.asInstanceOf[js.Any])
Expand Down

0 comments on commit e656516

Please sign in to comment.