JetBrains/kotlin-wrappers

How do you get an ElementNode for react-router using react class-components?

Closed this issue · 7 comments

We are migrating from old versions of react and their kotlin-wrappers. Hence we use old-school class-components and not react functional-components.

React-router-dom's Route needs an ElementNode for the element attribute. However, the child function used like this
Child(MyComponent::class)
which used to return ReactElement now returns nothing.

What is the correct class-component/"legacy" approach?

@TorRanfelt Do you want to use latest Kotlin Wrappers?
Could you provide screenshot of code (with error) which you need to fix?

Old version:

// The context is huge, but the issue is simple.

for ((contentPath, content) in routes) {
  route(path = contentPath, exact = true) {
    content(contentPath) // content returns the ReactElement created by the child function used to create a class-component.
  }
}

New version:

for ((contentPath, content) in routes) {
  Route {
      attrs.path = contentPath
      attrs.element = content(path) // The problem is that since child now returns Unit I don't have anything to pass along, but the attribute element is a ReactNode.
  }
}

We are migrating from old versions of react-wrappers back when they were on jcenter to the versions on maven that lead to the least migration-hassle (we have a web-app for each year and the older years just need to be brought up to react versions that has wrappers that exists on maven).

Old versions:
org.jetbrains:kotlin-react:16.13.1-pre.124-kotlin-1.4.10
org.jetbrains:kotlin-react-dom:16.13.1-pre.124-kotlin-1.4.10
org.jetbrains:kotlin-react-router-dom:5.1.2-pre.125-kotlin-1.4.10

New versions:
org.jetbrains.kotlin-wrappers:kotlin-react-legacy:17.0.2-pre.323-kotlin-1.6.10
org.jetbrains.kotlin-wrappers:kotlin-react-dom-legacy:17.0.2-pre.323-kotlin-1.6.10
org.jetbrains.kotlin-wrappers:kotlin-react-router-dom:6.2.2-pre.324-kotlin-1.6.10

But as far as I can tell this specific issue would be the same with the latest wrappers since Route expect a ReactNode but creating a class-component with child gives you nothing to pass along. How is this instead supposed to be done?

You can use react.createElement to create ReactNode from class component

So if I wanted the content function to return the class-component MyComponent I would do this:

fun RBuilder.myComponent(
  foo: String
) = child(MyComponent::class) {
  attrs.foo = foo
}

// In a content-function:
createElement<MyComponentProps> { // Using the props of MyComponent.
  myComponent("bar")
}

RBuilder extensions aren't recommended :(

Components for routes is what you need.
Functional components or class components - both work.
In latest Router v6 you can set component for route.
Component for route must have empty props.

RBuilder extensions aren't recommended :(

Too late to change that on a whim in our huge project. - I think we did that because that's how it was done in the original examples 6 years ago. Although I'm curious what the problem is.

Components for routes is what you need. Functional components or class components - both work. In latest Router v6 you can set component for route. Component for route must have empty props.

Looks like "Components for routes" and RouteObject for complicated paths would be the way to go if starting over on routing, but right now I really need to just get to the other sides for all the previous years.

Working with refactoring what we got I'm getting the impression this is how to do it.

for ((contentPath, content) in routes) {
  Route {
      attrs.path = contentPath
      attrs.element = createElement<Props> { content(path) }
  }
}

// An example of a content function
fun RBuilder.foo() {
  child(MyComponent::class) {}
}

Although I'm curious what the problem is.

  1. No isolation.
    You just build 1 big component (with multiple nodes) with function helpers.
  2. It's unsafe to call React hooks inside such functions, because you don't know how much times your extension will be called.

If your initial problem is solved - please close issue :)