2015-06-11 2 views
6

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

Demo

У меня есть следующий ES6 код

const {createFactory, createClass, DOM: { label, input, button }} = React; 

const tester = createFactory(createClass({ 
    render() { 
     return label({} 
       ,`Name: ${this.props.name}` 
       ,input({defaultValue: this.props.name}) 
       ,button({onClick: this.changeName}, "Change") 
      ) 
    }, 
    changeName() { 
    this.setProps({name: "Wilma"}) 
    } 
})) 

React.render(tester({name: "Fred"}), document.querySelector('body')) 

Нажатие кнопки явно изменяет реквизита, но старый defaultValue все еще находится на входе! Так что же дает? Что я делаю не так? это ошибка? Есть ли обходной путь?

+1

Больше информации здесь: https://github.com/facebook/react/issues/4101 –

ответ

5

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

,input({value: this.props.name}) 

Измените значение при изменении этого.props.name.

http://output.jsbin.com/melitecimo

+2

да, я знаю, что 'делает value', но и блокирует вход так, что он не может измениться. Множество рабочих процессов, чтобы обойти это, но это простой сценарий, в котором [реакционные документы, похоже, рекомендуют использовать defaultValue] (http://facebook.github.io/react/docs/forms.html#uncontrolled-components). В любом случае, это не является хорошей причиной для того, что скрытно хранит состояние в DOM –

+1

'defaultValue' определяет только начальное значение компонента при монтаже. Ожидается, что поведение его ценности будет продолжать изменяться с помощью реквизита, который вы ему дали. Я бы рекомендовал что-то вроде LinkedStateMixin, но я не уверен, насколько хорошо он ведет себя с es6. https://facebook.github.io/react/docs/two-way-binding-helpers.html, если вам интересно. –

+2

Правильный ответ, но [я действительно вижу это как ошибку] ​​(https://github.com/facebook/react/issues/4101) –

10

Я нашел то, что кажется довольно хорошим решением этой проблемы: Используйте key опору, чтобы заставить отрисовку совершенно новый input.

В моем конкретном случае, я не нужен input, чтобы управлять своей собственной onChange реквизита, как form вокруг нее, в конечном счете контролирует государство в какой-то магазин, который заполнит defaultValue. Но состояние хранилища может быть асинхронно инициализировано/обновлено, и в этом случае необходимо обновить defaultValue. Так вот сжатая версия моего конкретного случая:

import React, { PropTypes } from 'react'; 
import { Form } from 'provide-page'; 

const GatherContact = ({ 
    classes, 
    onSubmit, 
    movingContactName, 
    movingContactEmail, 
    movingContactPhone, 
    userName, 
    userEmail, 
    userPhone 
}) => (
    <Form onSubmit={onSubmit}> 
    <div className={classes.GatherContact}> 
     <h2 className={classes.GatherHeading}> 
     How can we contact you? 
     </h2> 

     <input 
     type="text" 
     className={classes.GatherContactInput} 
     placeholder="Name" 
     name="movingContactName" 
     key={`movingContactName:${movingContactName || userName}`} 
     defaultValue={movingContactName || userName} 
     required={true} 
     /> 

     <input 
     type="email" 
     className={classes.GatherContactInput} 
     placeholder="Email" 
     name="movingContactEmail" 
     key={`movingContactEmail:${movingContactEmail || userEmail}`} 
     defaultValue={movingContactEmail || userEmail} 
     required={true} 
     /> 

     <input 
     type="tel" 
     className={classes.GatherContactInput} 
     placeholder="Phone" 
     name="movingContactPhone" 
     key={`movingContactPhone:${movingContactPhone || userPhone}`} 
     defaultValue={movingContactPhone || userPhone} 
     required={true} 
     /> 

     {userName 
     ? undefined 
     : (
      <input 
      type="password" 
      className={classes.GatherContactInput} 
      placeholder="Password" 
      name="userPassword" 
      required={true} 
      autoComplete="new-password" 
      /> 
     ) 
     } 
    </div> 
    </Form> 
); 

GatherContact.propTypes = { 
    classes: PropTypes.object.isRequired, 
    onSubmit: PropTypes.func.isRequired, 
    movingContactName: PropTypes.string.isRequired, 
    movingContactEmail: PropTypes.string.isRequired, 
    movingContactPhone: PropTypes.string.isRequired, 
    userName: PropTypes.string.isRequired, 
    userEmail: PropTypes.string.isRequired, 
    userPhone: PropTypes.string.isRequired 
}; 

export default GatherContact; 
+1

Это решение работало очень хорошо для меня, спасибо. Но я немного смущен, почему свойство «ключ» и почему это работает? Помимо этого обходного пути, каково свойство «ключа», которое предполагается сделать для ввода? Он не отображается в документации. Будет ли это обходное решение работать с любым другим именем свойства, отличным от «ключа»? –

+2

@DavidNeto React использует свойство 'key', чтобы знать, как обновлять дочерние узлы. Если «ключ» должен оставаться тем же, он будет использовать один и тот же точный узел DOM и обновлять его атрибуты по мере необходимости. Но поскольку «ключ» изменяется, он отображает совершенно новый узел DOM. – timbur

+0

спасибо!это было именно то, что мне нужно для принудительного повторного рендеринга, когда меняются только изменения по умолчанию (мне нужно изменить только значение по умолчанию для изменения календаря - rc-calendar - обновление локали) – abidibo

Смежные вопросы