Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't initialize properties in constructor when using strict #1507

Closed
josh-endries opened this issue Apr 19, 2018 · 4 comments
Closed

Can't initialize properties in constructor when using strict #1507

josh-endries opened this issue Apr 19, 2018 · 4 comments

Comments

@josh-endries
Copy link

Yeah that checkbox template just doesn't lend itself to readable reporting.

I'm having an issue with MobX 4.2.0 (TS 2.8.1) wherein properties initialized in constructors are causing errors if I use enforceActions: 'strict'. I posted this on StackOverflow, which led me to what I would consider a workaround, using another @action method to initialize the class which gets called by constructor. However, I feel that the constructor should be allowed to do this normally... The error message is:

Uncaught Error: [mobx] Since strict-mode is enabled, changing observed observable values outside actions is not allowed. Please wrap the code in an `action` if this change is intended. Tried to modify: AppState@1.timer
    at invariant (mobx.module.js:2704)
    at fail$1 (mobx.module.js:2699)
    at checkIfStateModificationsAreAllowed (mobx.module.js:3303)
    at ObservableValue.prepareNewValue (mobx.module.js:997)
    at ObservableObjectAdministration.write (mobx.module.js:1093)
    at AppState.set [as timer] (mobx.module.js:1257)
    at AppState.set [as timer] (mobx.module.js:143)
    at new AppState (index.tsx:26)
    at eval (index.tsx:66)

This has been reported before in #563 and #338 so maybe this is a regression, but I would lean more towards my code being wrong since I'm new to MobX. In both of those it was mentioned that this has been fixed or obsoleted. Maybe what I'm doing isn't quite the same. This is the code that causes the error:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import * as MobX from 'mobx';
import * as MobXReact from 'mobx-react';
import DevTools from 'mobx-react-devtools';

MobX.configure({
	enforceActions: 'strict'
});

class AppState {
	@MobX.observable
	public timer = 0;

	public constructor() {
		setInterval(() => {
			this.incrTimer();
		}, 1000);
	}

	@MobX.action
	public incrTimer() {
		this.timer += 1;
	}

	@MobX.action
	public resetTimer() {
		this.timer = 0;
	}
}

@MobXReact.observer
class TimerView extends React.Component<{appState: AppState}, {}> {
	render() {
		return (
			<div>
				<button onClick={this.onReset}>
					Seconds passed: {this.props.appState.timer}
				</button>
				<DevTools/>
			</div>
		);
	}

	onReset = () => {
		this.props.appState.resetTimer();
	}
};

const appState = new AppState();
const rootNode = document.body.appendChild(document.createElement('div'));

ReactDOM.render(<TimerView appState={appState} />, rootNode);

The JavaScript that gets emitted by TypeScript includes this constructor (which is where the error occurs):

    constructor() {
        this.timer = 0;
        setInterval(() => {
            this.incrTimer();
        }, 1000);
    }

The setInterval code actually doesn't matter, that works fine, I assume because it calls incrTimer which is an action (which is why I did that). The problem is this.timer = 0;. If I get rid of that and call resetTimer just after creating the object, or call some private action initialization function, it works fine. I'm new to MobX's idiosyncrasies so maybe somehow timer is being observed already before constructor finishes? From the other issues it sounded like this shouldn't be an issue any more.

@urugator
Copy link
Collaborator

use true instead of strict:

MobX.configure({
	enforceActions: true
});

See #1473 for details

@josh-endries
Copy link
Author

I guess I don't understand, what is observing the property before it's created in the constructor?

@urugator
Copy link
Collaborator

Nothing... "strict" is newly added option to force action for any observable mutation no matter what (it doesn't matter whether observable is observed by something or not...)

@mweststrate
Copy link
Member

Question has been answered, the behavior is as intended (arguably it would be nice to be able to exclude make an exception for constructor functions, but this is not detectable at runtime)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants