React.js: избегать обновлений текущего редактируемого ввода

Double-conversion problem

Демонстрация: jsfiddle

/**
 * @jsx React.DOM
 */
var NumberField = React.createClass({
    render: function() {
        return <input type="number" value={this.props.value} onInput={this.onInput}/>;
    },
    onInput: function(e) {
        if (!this.props.onValueChange) {
            return;
        }
        var value = parseInt(e.target.value, 10);
        return this.props.onValueChange(value);
    }
});

var TempConverter = React.createClass({
    getInitialState: function() {
        return {c: 0};
    },
    render: function() {
        var c = this.state.c;
        return <p>
            <NumberField onValueChange={this.onChangeC} value={c}/> C
            <br/>
            <NumberField onValueChange={this.onChangeF} value={c2f(c)}/> F
        </p>;
    },
    onChangeC: function(c) {
        this.setState({c: c});
    },
    onChangeF: function(f) {
        this.setState({c: f2c(f)});
    }
});


function c2f(c) {
    return 1.8 * c + 32;
}
function f2c(f) {
    return 0.5555555555555 * (f - 32);
}

Когда я меняю значение ° F на единицу, оно преобразуется в градусы Цельсия, а затем обратно в градусы Фаренгейта, что приводит к ошибкам округления.

Есть ли способ избежать обновлений в данный момент измененного элемента?

punch back

Backbone.js имеет точно такую же проблему.

Ответ 1

Вы спрашиваете,

Есть ли способ избежать обновлений в данный момент измененного элемента?

В общем не очень. На самом деле это особенность React: ваш пользовательский интерфейс всегда будет синхронизирован с вашими данными! Конечно, переопределяя shouldComponentUpdate и выполняя некоторую ручную работу, вы можете предотвратить изменение полей, но преднамеренно, что путь наименьшего сопротивления приводит вас к всегда точному пользовательскому интерфейсу.

Звучит так, будто вы хотите иметь возможность показывать либо точную температуру ° C, либо точную температуру ° F, поэтому, похоже, наилучший подход здесь заключается в ее сохранении. В противном случае вы притворяетесь более точным, чем на самом деле. Я изменил ваш код так, чтобы он работал в одном из двух режимов: в режиме Цельсия или в градусах Фаренгейта:

var TempConverter = React.createClass({
    getInitialState: function() {
        return {type: "c", val: 0};
    },
    render: function() {
        var c, f;
        if (this.state.type === "c") {
            c = this.state.val;
            f = c2f(c);
        } else {
            f = this.state.val;
            c = f2c(f);
        }

Отслеживая значение таким образом, вы можете хранить и отображать точную температуру, введенную пользователем, и быть уверенным, что вы не потеряете никакой точности.

Демонстрационная версия здесь: jsfiddle

(Конечно, вы также можете округлить температуру перед отображением, но ваш ответ на вопрос Backbone.js указывает, что это не ваше предпочтительное решение.)