ManuelDeLeon / viewmodel-react

Create your React components with view models.
MIT License
24 stars 3 forks source link

b="defer:true" on react-route with Meteor 1.7/1.8 #47

Open wildhart opened 6 years ago

wildhart commented 6 years ago

I've tried upgrading from Meteor 1.6 to Meteor 1.7 then Meteor 1.8, and with both b="defer:true" in a react-route no longer compiles:

<Route path="/privacy" render={props => <PolicyPrivacy b="defer: true" {...props} /> } />

gives this compile error:

Property body of ArrowFunctionExpression expected node to be of a type ["BlockStatement","Expression"] but instead got "JSXExpressionContainer"

It was working perfectly before.

I've upgraded to Meteor 1.8 with:

    "@babel/runtime": "^7.1.2",
    "babel-runtime": "^6.18.0",
    ...
    "react": "^15.4.2",
    "react-dom": "^15.4.2",
    "react-helmet": "^5.2.0",
    "react-router-dom": "^4.3.1",
    ...
    "viewmodel-react": "^3.1.4",
    "viewmodel-react-plugin": "^3.1.4",
    "webfontloader": "^1.6.28"
  },
  "babel": {
    "presets": [ "es2015",  "react" ],
    "plugins": [ "viewmodel-react-plugin" ]
  },

Any ideas?

wildhart commented 6 years ago

Sorry, I forgot I'd already raised this here https://github.com/ManuelDeLeon/viewmodel-react-plugin/issues/4

I had given up on upgrading Meteor for a while, but wanted to try again. Any new help would be appreciated though.

antoninadert commented 5 years ago

I know this is a dirty hack but your route could point to a component that would encapsulate your deferred component...

I had problems with defer binding with Inferno, and am not sure how they are managed internally

wildhart commented 5 years ago

Hi @antoninadert ,

That's exactly what I ended up doing. It's a bit tricky because you can't pass a path variable to an import(path) statement. Instead every deferred route needs it's own import() statement. I can't remember where I found this code:

// Defer.jsx
import React, { Component } from 'react';

export class Defer extends Component {
    _isMounted = true;
    state = {
        Bar: null
    };
    componentWillMount() {
        let p;
        switch (this.props.d) {
            case 'AppHome': p = import('./AppHome/AppHome'); break;
            case 'Help': p = import('./Help/Help'); break;
            case 'Edit': p = import('./Edit/Edit'); break;
            // etc...
        }
        p && p.then(mod => this._isMounted && this.setState({Bar: mod[this.props.d]})).catch(error => console.log('defer error: ', error));
    }
    componentDidUpdate(prevProps, prevState) {
        if (this.props.d && this.props.d != prevProps.d) this.componentWillMount();
    }
    componentWillUnmount() {
        this._isMounted = false;
    }
    render() {
        let {Bar} = this.state;
        return Bar ? <Bar {...this.props} /> : null;
    }
}

Then I can do this:

<Switch>
    <Route path="/app" render={(props) => <Defer d="AppHome" {...props} />} />
    <Route path="/help" render={(props) => <Defer d="Help" {...props} />} />
</Switch>