Flow-Router using React.Component causes ReferenceError


#1

Hi there! I’ve been using FlowRouter successfully for a couple years now. However, in light of React 16’s changes, I’m slowly converting all my components from React.createClass to extends React.Component. Doing this on components mounted via FlowRouter seems to cause all sorts of issues though. Here’s an example:

import React from 'react'
import { FlowRouter } from 'meteor/ostrio:flow-router-extra'
import {mount} from 'react-mounter'
FlowRouter.route('/terms', {
    name: 'terms',
    async action(params, queryParams) {
        await import('/imports/client/terms') 
        mount(Layout, {
            content: <Terms />,
        })
    }
})

And here’s my component:

import React from 'react'
export default class Terms extends React.Component {
    constructor(props) {
        super(props)
    }

    render() {
        return (
            <div>Hello world!</div>
        )
    }
}

This result in the following error: Uncaught (in promise) ReferenceError: Terms is not defined

If I switch back to React.createClass, everything works perfectly. Any thoughts?


#2

Hello there,

Not a React expert, but in this thread, I was trying to answer the similar question.
Earlier we added, yet undocumented, React Composer helpers - see this thread.

Can’t help you with the error, but hope you will find some clue in the links above.


#3

Thanks for the tips! Unfortunately no clues there :frowning:


#4

What if you do it this way?:

import React from 'react'
import { FlowRouter } from 'meteor/ostrio:flow-router-extra'
import {mount} from 'react-mounter'
FlowRouter.route('/terms', {
    name: 'terms',
    action(params, queryParams) { 
        mount(Layout, {
            content: <Terms />,
        })
    },
    waitOn() {
        return import('/imports/client/terms');
    }
})

According to the error Terms is not defined.
Shouldn’t it be somewhere defined as variable at the scope of the file?


#5

Exact same problem, unfortunately. As soon as I switch the component from export default Terms = React.createClass({ to export default class Terms extends React.Component { it stops working.


#6

I’ll start debugging with making Terms global variable, like window.Terms = ....

it stops working.

What do you mean? Error?


#7

If I use React.createClass, everything works fine. If I change it to React.Component then I get Uncaught (in promise) ReferenceError: Terms is not defined. One possible I read was that react-mount might only be able to handle stateless components… so I tried to just do a simple export const Terms = () => {return <div>Hello</div>} but had no luck with that either.


#8

Can’t help you with React, haven’t used it.
Hope other folks will help you. Or you can ask it on the React GitHub rep. This is definitely React specific question.


#9

Try it this way:

import React from 'react'
import { FlowRouter } from 'meteor/ostrio:flow-router-extra'
import {mount} from 'react-mounter'
FlowRouter.route('/terms', {
    name: 'terms',
    action(params, queryParams) {
        import('/imports/client/terms').then((Terms) => { // -> with or without {} brackets
            console.log(Terms); // <- What its output?
            mount(Layout, {
                content: <Terms />,
            })
        })
    }
})

Taken from here: Meteor 1.5: How to actually dynamically import modules?


#10

Getting much closer! It seems to import it just fine – now it’s just a matter of getting the content to render nicely.

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

#11

Okay, at least import is importing :slight_smile: now.
React.createElement is 100% React specific now.
Keep this thread updated - I would like to add working example to FlowRouter docs


#12

Try this:

FlowRouter.route('/terms', {
    name: 'terms',
    async action(params) {
      const {
        default: Terms,
      } = await import('/imports/client/terms')
      mount(Layout, {
        content: () => <Terms {...params} />,
      })
    },
  })

#13

That one works if I use export default Terms = React.createClass, but again fails with export default class Terms extends React.Component with the error Uncaught (in promise) ReferenceError: Terms is not defined :frowning:


#14

What is the output of this console.log ??


#15

Apologies, I was wrong. I hadn’t properly implemented your code (was accidentally overriding the route). Turns out the only thing I needed to do differently in yours was to do content: <Terms /> instead of content: () => <Terms />.

Final solution (yay!!!):

FlowRouter.route('/terms', {
    name: 'terms',
    async action(params) {
        const { default: Terms } = await import('/imports/client/terms')
        mount(Layout, {
            content: <Terms />,
        })
    },
})

And then the Terms component looks like:

import React from 'react'
export default class Terms extends React.Component {
    render() {
        return (
            <div>Hello world!</div>
        )
    }
}