React - изменить значение defaultValue, передав реквизиты

Рассмотрим следующий пример:

var Field = React.createClass({
    render: function () {
        // never renders new value...
        return (
            <div>
                <input type="text" defaultValue={this.props.value || ''} />
            </div>
        );
    }
});

var App = React.createClass({
    getInitialState: function () {
        return {value: 'Hello!'};
    },

    changeTo: function (str) {
        this.setState({value: str});
    },

    render: function () {
        return (
            <div>
                <Field value={this.state.value} />
                <button onClick={this.changeTo.bind(null, 'Whyyyy?')}>Change to "Whyyyy?"</button>
                <button onClick={this.changeTo.bind(null, void 0)}>Change to undefined</button>
            </div>
        );
    }
});

React.render(
    <App />,
    document.getElementById('app')
);

Я хочу передать значение в defaultValue в качестве поддержки немого входного компонента. Однако он никогда не повторяет его.

Ответ 1

Как упоминалось ранее, defaultValue устанавливается только при начальной загрузке для формы. После этого он не будет обновляться "естественно", потому что целью было только установить начальное значение по умолчанию.

Вы можете обойти это, если вам нужно, передав key компоненту обертки, например, на ваш компонент Field или App, хотя в более практических обстоятельствах он, вероятно, будет компонентом form, Хороший key будет уникальным значением для ресурса, передаваемого форме - например, идентификатора, хранящегося в базе данных, например.

В упрощенном случае вы можете сделать это в своем поле:

<div key={this.props.value}>
    <input type="text" defaultValue={this.props.value || ''} />
</div>

В случае более сложной формы что-то вроде этого может получить то, что вы хотите, например, ваше действие onSubmit, представленное в API, но остающееся на одной странице:

const Form = ({item, onSubmit}) => {
  return (
    <form onSubmit={onSubmit} key={item.id}>
      <label>
        First Name
        <input type="text" name="firstName" defaultValue={item.firstName} />
      </label>
      <label>
        Last Name
        <input type="text" name="lastName" defaultValue={item.lastName} />
      </label>
      <button>Submit!</button>
    </form>
  )
}

Form.defaultProps = {
  item: {}
}

Form.propTypes = {
  item: PropTypes.object,
  onSubmit: PropTypes.func.isRequired
}

При использовании неконтролируемых входных данных формы мы обычно не заботимся о значениях до тех пор, пока они не будут отправлены, поэтому почему это более идеально, чтобы только принудительно повторно отобразить, когда вы действительно хотите обновить defaultValues ​​(после отправки, а не при каждом изменении индивидуального ввода).

Если вы также редактируете одну и ту же форму и боитесь, что ответ API может вернуться с разными значениями, вы можете предоставить объединенный ключ чего-то вроде id plus timestamp.

Ответ 2

defaultValue работает только для начальной загрузки. После этого он не будет обновляться. Вам необходимо сохранить состояние для вас. Компонент Field:

var Field = React.createClass({
    //transfer props to state on load
    getInitialState: function () {
        return {value: this.props.value};
    },
    //if the parent component updates the prop, force re-render
    componentWillReceiveProps: function(nextProps) {
         this.setState({value: nextProps.value});
    },
    //re-render when input changes
    _handleChange: function (e){
        this.setState({value: e.target.value});
    },
    render: function () {
        // render based on state
        return (
            <div>
                <input type="text" onChange={this._handleChange} 
                                   value={this.state.value || ''} />
            </div>
        );
    }
});

Ответ 3

Я абсолютно уверен, что это связано с контролируемым и неконтролируемым входами.

Если я правильно понял, так как ваш <input> не контролируется (не определяет атрибут value), тогда значение всегда будет разрешено к значению, с которым оно инициализируется. В этом случае Hello!.

Чтобы преодолеть эту проблему, вы можете добавить атрибут value и установить его во время onChange:

var Field = React.createClass({
      render: function () {
          // never renders new value...
          return (
              <div>
                  <input type="text" defaultValue={this.props.default || ''} value={this.props.value} />
              </div>
          );
      }
  });

Вот плункер, показывающий изменение.

Ответ 4

Я также сталкиваюсь с этой проблемой, я сделал это, чтобы вручную обновить входное значение, когда реквизит изменился. Добавьте это в поле Поле реакции:

componentWillReceiveProps(nextProps){
    if(nextProps.value != this.props.value) {
        document.getElementById(<element_id>).value = nextProps.value
    }
}

Вам просто нужно добавить атрибут id в свой элемент, чтобы он мог быть расположен.

Ответ 5

Проблема здесь:

onClick={this.changeTo.bind(null, 'Whyyyy?')}

Мне любопытно, почему вы привязываетесь к null.

Вы хотите привязать к 'this', чтобы changeTo установилState в этом объекте.

Попробуйте это

<button onClick={this.changeTo.bind(this, 'Whyyyy?')}>Change to "Whyyyy?"</button>
<button onClick={this.changeTo.bind(this, void 0)}>Change to undefined</button>

В Javascript, когда функция вызывается, ее вызывал в области, из которой она была вызвана, а не там, где она была написана (я знаю, кажется встречной интуитивной). Чтобы убедиться, что он вызывается в контексте, который вы его пишете, вам нужно ".bind(this)".

Чтобы узнать больше о привязке и области действия, есть много онлайн-тэтов (намного лучше других) - вам может понравиться эта: http://ryanmorr.com/understanding-scope-and-context-in-javascript/

Я также рекомендую использовать инструменты React Dev, если вы используете firefox или chrome, таким образом вы могли бы видеть, что state.message не меняется: https://facebook.github.io/react/blog/2015/09/02/new-react-developer-tools.html