ManuelDeLeon / viewmodel-react

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

Upgrading 2.4.1 -> 3.0.0 causes lots of this.foo() is not a function errors #44

Open wildhart opened 6 years ago

wildhart commented 6 years ago

I tried updating viewmodel-react and viewmodel-react-plugin to their latest versions (from 2.4.1 and 3.0.3), but now I get lots of client runtime errors like

Uncaught TypeError: this.foo() is not a function

where foo is a viewModel property which was previously working fine. I narrowed it down to the upgrade of viewmodel-react from 2.4.1 to 3.0.0. I've successfully upgraded viewmodel-react-plugin to 3.1.4.

My package.json includes:

  "babel": {
    "presets": [
      "es2015",
      "react"
    ],
    "plugins": [
      "viewmodel-react-plugin"
    ]
  }

I'm also using Meteor's tracker with:

import ViewModel from 'viewmodel-react';
import { Tracker } from 'meteor/tracker';
ViewModel.Tracker = Tracker;

Any ideas what could be causing this?

ManuelDeLeon commented 6 years ago

Use the latest versions of both:

    "viewmodel-react": "^3.1.3",
    "viewmodel-react-plugin": "^3.1.4"

See https://github.com/ManuelDeLeon/meteor-ssr

wildhart commented 6 years ago

I tried that. I started with the latest versions of both modules, then reverted viewmodel-react back to earlier and earlier versions until the errors went away when I got back to viewmodel-react@2.4.1.

I've also updated all other modules to match your meteor-ssr starter project.

Something changes between 2.4.1 and 3.0.0 which breaks my project. Is there anything else I could try?

ManuelDeLeon commented 6 years ago

Need a repro then. Take a component that's failing and copy it to a new project with its parent and maybe child (if the failing prop is passed down).

On Mon, Jul 9, 2018, 4:04 AM wildhart notifications@github.com wrote:

I tried that. I started with the latest versions of both modules, then reverted viewmodel-react back to earlier and earlier versions until the errors went away when I got back to viewmodel-react@2.4.1.

I've also updated all other modules to match your meteor-ssr starter project.

Something changes between 2.4.1 and 3.0.0 which breaks my project. Is there anything else I could try?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/ManuelDeLeon/viewmodel-react/issues/44#issuecomment-403411180, or mute the thread https://github.com/notifications/unsubscribe-auth/AED31lAC6WRiWQuemEuZYkq2d95xlxLdks5uExywgaJpZM4VGqcK .

wildhart commented 6 years ago

While trying to cut my app down into a repro I've narrowed the bug down to differing behaviour of VM functions when passed as callbacks. Here's an example:

AppLayout({
    created() {
        this.onLocationChange(this.props.location, "POP");
        this.props.history.listen(this.onLocationChange); // <--- This causes the problem
    },
    lastPath: null,
    onLocationChange(location, action) {
        console.log(this); // @2.4.1 this===AppLayout  @3.0.0 this===Window
        this.lastPath(location.pathname); // @3.0.0 this.lastPath() is not a function
    },
    render() {
        <div>
              <div>
                <Link to="/">Route 1</Link> <Link to="/2">Route 2</Link>
              </div>
              <main>
                <Switch>
                    <Route exact path="/" component={Index} />
                    <Route path="/2" component={Route2} />
                </Switch>
                <p>
                    lastPath: {this.lastPath()}
                </p>
              </main>
        </div>
    }
});

(this is a trivialised example, in reality onLocationChange() is doing a lot of other useful stuff).

With viewmodel-react@2.4.1, when onLocationChange() is called by this.props.history.listen the this object is set to the AppLayout VM, but with viewmodel-react@3.0.0 this===window

There are a few easy ways to work around this, e.g.

this.props.history.listen((...args) => this.onLocationChange(...args));

But why the difference between 2.4.1 & 3.0.0?

wildhart commented 6 years ago

This also causes a problem when VM functions are used as event handlers, e.g.

Contact({
    setContact() {
        console.log(this) // @3.0.0 this===window
        if (this.selectedId() == this._id()) return; // @3.0.0 this.selectedId is not a function
        Meteor.call('server.companySettings.updateContact', this.type(), this._id(), (err, result) => {
            if (!err) Toast("Contact updated");
        });        
    },

    render() {
        ...
        <input type="radio" name={this.type()}
            checked={this.selectedId()==this._id()} onChange={this.setContact} />
        ...
    }
});

This needs to be changed to onChange={()=>this.setContact()}

wildhart commented 6 years ago

I've uploaded repro.zip. this is a repro for this and also https://github.com/ManuelDeLeon/viewmodel-react-plugin/issues/4

See readme.md and most of the action is in imports/ui/AppLayout.jsx

ManuelDeLeon commented 6 years ago

@wildhart Try viewmodel-react@3.1.4, I don't the the errors and it rebuilds when AppLayout is changed.

Let me know if there's an issue.

wildhart commented 6 years ago

@3.1.4 seems to fix this issue - this is set to the component's object instead of Window. Thanks!

However, I still have ManuelDeLeon/viewmodel-react-plugin#4 .... See new comment there.