Simple-todos-react, uncontrolled input


#1

The example simple-todos-react is throwing a warning:
Warning: Task is changing an uncontrolled input of type checkbox to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.

Normally, I would extend a React.Component and have a constructor that initializes the component’s internals and bind any component events. The Meteor example, however, does not include a constructor. To update the props in the example, the Meteor method calls Tasks.update(), which I presume uses reactivity to somehow update the prop. How the prop is actually updated, however, is hidden, so I don’t know if it uses a set method or not. So, the novel things here are a missing constructor and having something hidden updating the props.

What is the “Meteor way” to have proper controlled input for a React app?

Also, the functions under Task reference this, but this is not bound in a visible constructor. What magic is going on? Is there a reference written up on how this is bound throughout the various places in Meteor code?


#2

Can you post the sample code here?

But nevertheless, here is a sample code to edit a document using a controlled input:

    constructor(props) {
        super(props);

        this.state = {
            input: null
        };
    }

    componentWillMount() {
        // if using a method call to retrieve data from server
        Meteor.call('method.name', {arguments: 'sample arguments'}, function(error, result) {
            if (error) {
                console.log(error);
            } else {
                this.setState({
                    input: result
                });
            }
        }.bind(this));
    }

    componentWillReceiveProps(nextProps) {
        // if using createContainer to retrieve data from server
        if (nextProps.input) {
            this.setState({
                input: nextProps.input
            });
        }
    }

    render() {
        return (
            <form>
                <input
                    type="text"
                    value={this.state.input}
                    onChange={(event) => this.setState({input: event.target.value})}
                />
            </form>
        );
    }
}

#3

The simple-todos-react example is doing it differently, which is what has me confused. I am unfamiliar with the glue between Meteor and React, so I don’t know what the preferred structure is.

The simple-todos-react repo is here: https://github.com/meteor/simple-todos-react

The particular code is Task.jsx, which is here: https://github.com/meteor/simple-todos-react/blob/master/imports/ui/Task.jsx

The checkbox state is changed via a Meteor reactivity cascade, caused by the Mongo update call here: https://github.com/meteor/simple-todos-react/blob/master/imports/api/tasks.js#L57

In the code, a constructor for the React component is explicitly avoided, and all component prop and state changes are handled via reactivity invoked from Meteor methods. While this is interesting and convenient, it feels different from what I am used to – I don’t set initial states and there is no opportunity to call set methods.


#4

That sample will produce the controlled input warning. Always use React’s this.state to control the value of an input if you wanted to use a controlled input

Meteor.call() is a method call (call from client to server) and is not reactive.


#5

The Meteor.call() is invoking Tasks.update() – it is my understanding that somehow Meteor is using that update as an opportunity to update the internals of the React component.

My thinking thus far is that either the example project is a little messy, or the integration between Meteor and React is not yet complete, with the former being more likely.


#6

Yep, it was the former.

It is actually a potential security issue to let the client update a collection directly. Ironically, the security section of the documentation warns against this.