0

SO...

I am running into the issue...

Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.

...and I have found the same response multiple times regarding "export default". Hopefully the solution to my problem is something simple regarding my TypeScript compilation, ECMA version compatibility, etc. but any help is appreciated.

tsconfig.json

{
  "compilerOptions": {
    "jsx": "react",
    "outDir": "dist"
  },
  "include": [
    "src/**/*"
  ]
}

I realize I am not specifying a "target" so tsc defaults to "es3" which I thought is best for backwards compatibility. I have tried updating to "es5" and this did not fix my issue.

server.ts

this.app.set("views", path.join(__dirname, "views"))
this.app.set("view engine", "js")

var engines = require('consolidate')
this.app.engine('js', engines.react)

Since I am specifying "react" for the "jsx" property in my tsconfig.json, my compiled files will be .js, but will still contain React.createElement, etc. calls, so I am specifying my express view engine for JS files to use the consolidate project's react engine. Previously I was using express-react-views, any input on my strategy here would be helpful.

index.tsx

import * as React from 'react'

interface HelloMessageProps {
    name: string
}

class HelloMessage extends React.Component<HelloMessageProps, {}> {
  render() {
    return <div>Hello {this.props.name}!</div>;
  }
}

index.ts

// ...
// routing code
// ...
let options: Object = {
    "name": "World"
};

res.render("index", options);

...any help is much appreciated!

Community
  • 1
  • 1
Lane
  • 685
  • 2
  • 10
  • 25

1 Answers1

1

Found out that my problem was that I was trying to "render" a view file (html, jade, etc.) when I actually didn't want to. So I don't need express-react-views nor consolidate and I can remove my code...

this.app.set("views", path.join(__dirname, "views"))
this.app.set("view engine", "js")

var engines = require('consolidate')
this.app.engine('js', engines.react)

...and update my index.ts file to be...

// ...
// routing code
// ...
let options: Object = {
    "name": "World"
};

const components = require('../../components')
const HelloMessage = React.createFactory(components.HelloMessage)

const ReactDOM = require('react-dom/server')
res.send(ReactDOM.renderToString(HelloMessage(options)));

...the key here being to perform the "rendering" (i.e. transformation to the final HTML) using the ReactDOM's renderToString method and simply sending that output to the response (res.send(...)) instead of attempting to render it (res.render(...)).

Lane
  • 685
  • 2
  • 10
  • 25