From e81543f7cb8abb73010f31885ae86ac9a566b3d8 Mon Sep 17 00:00:00 2001 From: Shogo Wada Date: Sat, 15 Apr 2017 19:38:15 -0500 Subject: [PATCH] Return ReactClass from ReactRedux.connectAdvanced()() --- README.md | 6 +- build.sbt | 2 +- .../todoappredux/ContainerComponents.scala | 81 +++++++++---------- .../PresentationalComponents.scala | 10 +-- .../reactjs/redux/ContainerComponent.scala | 47 ----------- .../redux/ContainerComponentFactory.scala | 20 +++++ .../scalajs/reactjs/redux/ReactRedux.scala | 2 +- 7 files changed, 69 insertions(+), 99 deletions(-) delete mode 100644 redux/src/main/scala/io/github/shogowada/scalajs/reactjs/redux/ContainerComponent.scala create mode 100644 redux/src/main/scala/io/github/shogowada/scalajs/reactjs/redux/ContainerComponentFactory.scala diff --git a/README.md b/README.md index 9461b4e..0633f28 100644 --- a/README.md +++ b/README.md @@ -44,9 +44,9 @@ ReactDOM.render(HelloWorld("World"), mountNode) 2. Depend on the libraries. ``` libraryDependencies ++= Seq( - "io.github.shogowada" %%% "scalajs-reactjs" % "0.8.0", // For react facade - "io.github.shogowada" %%% "scalajs-reactjs-router-dom" % "0.8.0", // Optional. For react-router-dom facade - "io.github.shogowada" %%% "scalajs-reactjs-redux" % "0.8.0" // Optional. For react-redux facade + "io.github.shogowada" %%% "scalajs-reactjs" % "0.9.0", // For react facade + "io.github.shogowada" %%% "scalajs-reactjs-router-dom" % "0.9.0", // Optional. For react-router-dom facade + "io.github.shogowada" %%% "scalajs-reactjs-redux" % "0.9.0" // Optional. For react-redux facade ) ``` diff --git a/build.sbt b/build.sbt index 5ddb0f3..a4f6b64 100644 --- a/build.sbt +++ b/build.sbt @@ -24,7 +24,7 @@ publishArtifact := false val commonSettings = Seq( organization := "io.github.shogowada", name := "scalajs-reactjs", - version := "0.8.1-SNAPSHOT", + version := "0.9.0", licenses := Seq("MIT" -> url("https://opensource.org/licenses/MIT")), homepage := Some(url("https://github.com/shogowada/scalajs-reactjs")), scalaVersion := "2.12.1", diff --git a/example/todo-app-redux/src/main/scala/io/github/shogowada/scalajs/reactjs/example/todoappredux/ContainerComponents.scala b/example/todo-app-redux/src/main/scala/io/github/shogowada/scalajs/reactjs/example/todoappredux/ContainerComponents.scala index d37a52f..d092010 100644 --- a/example/todo-app-redux/src/main/scala/io/github/shogowada/scalajs/reactjs/example/todoappredux/ContainerComponents.scala +++ b/example/todo-app-redux/src/main/scala/io/github/shogowada/scalajs/reactjs/example/todoappredux/ContainerComponents.scala @@ -1,6 +1,6 @@ package io.github.shogowada.scalajs.reactjs.example.todoappredux -import io.github.shogowada.scalajs.reactjs.VirtualDOM.VirtualDOMElements +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 @@ -19,47 +19,44 @@ object ContainerComponents { case class LinkContainerComponentOwnProps(filter: String) - implicit class RichVirtualDOMElements(virtualDOMElements: VirtualDOMElements) { - def LinkContainerComponent = ReactRedux.connectAdvanced( - (dispatch: Dispatch) => { - var ownProps: LinkContainerComponentOwnProps = null - val onClick: () => Unit = () => dispatch(SetVisibilityFilter(filter = ownProps.filter)) - - (state: State, nextOwnProps: LinkContainerComponentOwnProps) => { - ownProps = nextOwnProps - Link.WrappedProps( - active = ownProps.filter == state.visibilityFilter, - onClick = onClick - ) - } + def LinkContainerComponent: ReactClass = ReactRedux.connectAdvanced( + (dispatch: Dispatch) => { + var ownProps: LinkContainerComponentOwnProps = null + val onClick: () => Unit = () => dispatch(SetVisibilityFilter(filter = ownProps.filter)) + + (state: State, nextOwnProps: LinkContainerComponentOwnProps) => { + ownProps = nextOwnProps + Link.WrappedProps( + active = ownProps.filter == state.visibilityFilter, + onClick = onClick + ) } - )(Link(_)) // (Props[WrappedProps]) => ReactElement - - def TodoListContainerComponent = ReactRedux.connectAdvanced( - (dispatch: Dispatch) => { - val onTodoClick: (Int) => Unit = (id: Int) => dispatch(ToggleTodo(id = id)) - (state: State, ownProps: Unit) => { - TodoList.WrappedProps( - todos = state.visibilityFilter match { - case VisibilityFilters.ShowAll => state.todos - case VisibilityFilters.ShowActive => state.todos.filter(todo => !todo.completed) - case VisibilityFilters.ShowCompleted => state.todos.filter(todo => todo.completed) - }, - onTodoClick = onTodoClick - ) - } + } + )(Link(_)) // (Props[WrappedProps]) => ReactElement + + def TodoListContainerComponent: ReactClass = ReactRedux.connectAdvanced( + (dispatch: Dispatch) => { + val onTodoClick: (Int) => Unit = (id: Int) => dispatch(ToggleTodo(id = id)) + (state: State, ownProps: Unit) => { + TodoList.WrappedProps( + todos = state.visibilityFilter match { + case VisibilityFilters.ShowAll => state.todos + case VisibilityFilters.ShowActive => state.todos.filter(todo => !todo.completed) + case VisibilityFilters.ShowCompleted => state.todos.filter(todo => todo.completed) + }, + onTodoClick = onTodoClick + ) } - )(TodoList(_)) // (Props[WrappedProps]) => ReactElement - - def AddTodoContainerComponent = ReactRedux.connectAdvanced( - (dispatch: Dispatch) => { - val onAddTodo: (String) => Unit = (text: String) => dispatch(AddTodo(text = text)) - (state: State, ownProps: Unit) => - AddTodoComponent.WrappedProps( - onAddTodo = onAddTodo - ) - } - )(new AddTodoComponent()) // ReactClassSpec - } - + } + )(TodoList(_)) // (Props[WrappedProps]) => ReactElement + + def AddTodoContainerComponent: ReactClass = ReactRedux.connectAdvanced( + (dispatch: Dispatch) => { + val onAddTodo: (String) => Unit = (text: String) => dispatch(AddTodo(text = text)) + (state: State, ownProps: Unit) => + AddTodoComponent.WrappedProps( + onAddTodo = onAddTodo + ) + } + )(new AddTodoComponent()) // ReactClassSpec } diff --git a/example/todo-app-redux/src/main/scala/io/github/shogowada/scalajs/reactjs/example/todoappredux/PresentationalComponents.scala b/example/todo-app-redux/src/main/scala/io/github/shogowada/scalajs/reactjs/example/todoappredux/PresentationalComponents.scala index 55cf385..cd06354 100644 --- a/example/todo-app-redux/src/main/scala/io/github/shogowada/scalajs/reactjs/example/todoappredux/PresentationalComponents.scala +++ b/example/todo-app-redux/src/main/scala/io/github/shogowada/scalajs/reactjs/example/todoappredux/PresentationalComponents.scala @@ -56,20 +56,20 @@ object Footer { def apply(): ReactElement = <.p()( "Show: ", - <.LinkContainerComponent( + <(LinkContainerComponent)( // Make sure to wrap own props with "wrapped" property ^.wrapped := LinkContainerComponentOwnProps("SHOW_ALL") )( "All" ), ", ", - <.LinkContainerComponent( + <(LinkContainerComponent)( ^.wrapped := LinkContainerComponentOwnProps("SHOW_ACTIVE") )( "Active" ), ", ", - <.LinkContainerComponent( + <(LinkContainerComponent)( ^.wrapped := LinkContainerComponentOwnProps("SHOW_COMPLETED") )( "Completed" @@ -107,8 +107,8 @@ object AddTodoComponent { object App { def apply(): ReactElement = <.div()( - <.AddTodoContainerComponent.empty, - <.TodoListContainerComponent.empty, + <(AddTodoContainerComponent).empty, + <(TodoListContainerComponent).empty, Footer() ) } diff --git a/redux/src/main/scala/io/github/shogowada/scalajs/reactjs/redux/ContainerComponent.scala b/redux/src/main/scala/io/github/shogowada/scalajs/reactjs/redux/ContainerComponent.scala deleted file mode 100644 index 30f9940..0000000 --- a/redux/src/main/scala/io/github/shogowada/scalajs/reactjs/redux/ContainerComponent.scala +++ /dev/null @@ -1,47 +0,0 @@ -package io.github.shogowada.scalajs.reactjs.redux - -import io.github.shogowada.scalajs.reactjs.React -import io.github.shogowada.scalajs.reactjs.VirtualDOM.{VirtualDOMAttributes, VirtualDOMElements} -import io.github.shogowada.scalajs.reactjs.classes.ReactClass -import io.github.shogowada.scalajs.reactjs.classes.specs.ReactClassSpec -import io.github.shogowada.scalajs.reactjs.classes.specs.ReactClassSpec.Render -import io.github.shogowada.scalajs.reactjs.elements.ReactElement -import io.github.shogowada.statictags.Element - -import scala.scalajs.js - -object ContainerComponent { - def ownPropsFromNative[OwnProps](nativeOwnProps: js.Dynamic): OwnProps = - nativeOwnProps.wrapped.asInstanceOf[OwnProps] - - def ownPropsToNative[OwnProps](ownProps: OwnProps): js.Dynamic = - js.Dynamic.literal("wrapped" -> ownProps.asInstanceOf[js.Any]) -} - -class ContainerComponent(containerComponent: ReactClass) { - def apply(attributes: Any*)(children: Any*): ReactElement = { - React.createElement( - containerComponent, - VirtualDOMAttributes.toReactAttributes(Element.flattenAttributes(attributes)), - VirtualDOMElements.toReactElements(Element.flattenContents(children)): _* - ) - } - - def empty = this.apply()() -} - -class ContainerComponentFactory[WrappedProps](nativeFactory: js.Function1[js.Any, ReactClass]) { - def apply[State](classSpec: ReactClassSpec[WrappedProps, State]): ContainerComponent = - this.apply(React.createClass(classSpec)) - - def apply[State](reactClass: ReactClass): ContainerComponent = { - val nativeContainerComponent: ReactClass = nativeFactory(reactClass) - new ContainerComponent(nativeContainerComponent) - } - - def apply(render: Render[WrappedProps]): ContainerComponent = { - val nativeRender = ReactClassSpec.renderToNative(render) - val nativeContainerComponent: ReactClass = nativeFactory(nativeRender) - new ContainerComponent(nativeContainerComponent) - } -} diff --git a/redux/src/main/scala/io/github/shogowada/scalajs/reactjs/redux/ContainerComponentFactory.scala b/redux/src/main/scala/io/github/shogowada/scalajs/reactjs/redux/ContainerComponentFactory.scala new file mode 100644 index 0000000..5a9cb0f --- /dev/null +++ b/redux/src/main/scala/io/github/shogowada/scalajs/reactjs/redux/ContainerComponentFactory.scala @@ -0,0 +1,20 @@ +package io.github.shogowada.scalajs.reactjs.redux + +import io.github.shogowada.scalajs.reactjs.React +import io.github.shogowada.scalajs.reactjs.classes.ReactClass +import io.github.shogowada.scalajs.reactjs.classes.specs.ReactClassSpec +import io.github.shogowada.scalajs.reactjs.classes.specs.ReactClassSpec.Render + +import scala.scalajs.js + +class ContainerComponentFactory[WrappedProps](nativeFactory: js.Function1[js.Any, ReactClass]) { + def apply[State](classSpec: ReactClassSpec[WrappedProps, State]): ReactClass = + this.apply(React.createClass(classSpec)) + + def apply(reactClass: ReactClass): ReactClass = nativeFactory(reactClass) + + def apply(render: Render[WrappedProps]): ReactClass = { + val nativeRender = ReactClassSpec.renderToNative(render) + nativeFactory(nativeRender) + } +} diff --git a/redux/src/main/scala/io/github/shogowada/scalajs/reactjs/redux/ReactRedux.scala b/redux/src/main/scala/io/github/shogowada/scalajs/reactjs/redux/ReactRedux.scala index 6db1d5a..5f39087 100644 --- a/redux/src/main/scala/io/github/shogowada/scalajs/reactjs/redux/ReactRedux.scala +++ b/redux/src/main/scala/io/github/shogowada/scalajs/reactjs/redux/ReactRedux.scala @@ -52,7 +52,7 @@ object ReactRedux { selector: (ReduxState, OwnProps) => WrappedProps ): js.Function2[ReduxState, js.Dynamic, js.Any] = (state: ReduxState, nativeOwnProps: js.Dynamic) => { - val ownProps: OwnProps = ContainerComponent.ownPropsFromNative(nativeOwnProps) + val ownProps: OwnProps = ReactClassSpec.propsFromNative[OwnProps](nativeOwnProps).wrapped val wrappedProps: WrappedProps = selector(state, ownProps) val nativeProps = clone(nativeOwnProps) nativeProps.updateDynamic(ReactClassSpec.WrappedProperty)(wrappedProps.asInstanceOf[js.Any])