2016-12-08 1 views
4

Я ищу, чтобы создать компонент без гражданства, вход которого может быть проверен родительским элементом.Как я могу привязать к рефлектору компонента без гражданства в React?

В моем примере ниже я столкнулся с проблемой, когда входной рефлектор никогда не назначается собственному _emailAddress родительскому объекту.

Когда handleSubmit называется, this._emailAddress является undefined. Есть что-то, чего я не хватает, или есть лучший способ сделать это?

interface FormTestState { 
    errors: string; 
} 

class FormTest extends React.Component<void, FormTestState> { 
    componentWillMount() { 
     this.setState({ errors: '' }); 
    } 

    render(): JSX.Element { 
     return (
      <main role='main' className='about_us'>    
       <form onSubmit={this._handleSubmit.bind(this)}> 
        <TextInput 
         label='email' 
         inputName='txtInput' 
         ariaLabel='email' 
         validation={this.state.errors} 
         ref={r => this._emailAddress = r} 
        /> 

        <button type='submit'>submit</button> 
       </form> 
      </main> 
     ); 
    } 

    private _emailAddress: HTMLInputElement; 

    private _handleSubmit(event: Event): void { 
     event.preventDefault(); 
     // this._emailAddress is undefined 
     if (!Validators.isEmail(this._emailAddress.value)) { 
      this.setState({ errors: 'Please enter an email address.' }); 
     } else { 
      this.setState({ errors: 'All Good.' }); 
     } 
    } 
} 

const TextInput = ({ label, inputName, ariaLabel, validation, ref }: { label: string; inputName: string; ariaLabel: string; validation?: string; ref: (ref: HTMLInputElement) => void }) => (
    <div> 
     <label htmlFor='txt_register_first_name'> 
      { label } 
     </label> 

     <input type='text' id={inputName} name={inputName} className='input ' aria-label={ariaLabel} ref={ref} /> 

     <div className='input_validation'> 
      <span>{validation}</span> 
     </div> 
    </div> 
); 
+0

Добавить 'console.log' к вашей реф функции, чтобы увидеть, если она называется –

+0

Возможная Дубликат [React лица без компонента this.refs..value?] (Http://stackoverflow.com/questions/ 37266411/response-stateless-component-this-refs-value) –

ответ

11

Вы не можете получить доступ к React как методы (например, componentDidMount, componentWillReceiveProps и т.д.) на лиц без компонентов, в том числе refs. Checkout this discussion on GH для полного состава.

Идея безгражданства заключается в том, что для него нет экземпляра (состояния). Таким образом, вы не можете присоединить ref, так как нет никакого государства для присоединения ref.

Лучше всего было бы пройти обратный вызов, когда компонент изменится, а затем присвойте этот текст состоянию родителя.

Или вы можете вообще отказаться от компонента без гражданства и использовать компонент нормального класса.

From the docs...

Вы не можете использовать атрибут реф на функциональных компонентах, поскольку они не имеют экземпляров. Однако вы можете использовать атрибут ref внутри функции рендеринга функционального компонента.

function CustomTextInput(props) { 
    // textInput must be declared here so the ref callback can refer to it 
    let textInput = null; 

    function handleClick() { 
    textInput.focus(); 
    } 

    return (
    <div> 
     <input 
     type="text" 
     ref={(input) => { textInput = input; }} /> 
     <input 
     type="button" 
     value="Focus the text input" 
     onClick={handleClick} 
     /> 
    </div> 
); 
} 
+0

Я получаю сообщение об ошибке 'textInput.focus' не является функцией – jasan

+0

@jasan вы обертываете свой ввод в другой компонент? если это так, вам нужно выставить метод фокусировки для этого класса.Если у вас по-прежнему возникает проблема, проверьте значение textInput, когда вы вызываете фокус. –

+0

да, я использую поле из редукционной формы. Я нашел решение. ура – jasan

1

Значение вашего TextInput является не более чем состоянием вашего компонента. Поэтому вместо того, чтобы получать текущее значение с помощью ссылки (плохая идея в целом, насколько я знаю), вы можете получить текущее состояние.

В уменьшенной версии (без типирования):

class Form extends React.Component { 
    constructor() { 
    this.state = { _emailAddress: '' }; 

    this.updateEmailAddress = this.updateEmailAddress.bind(this); 
    this.handleSubmit = this.handleSubmit.bind(this); 
    } 

    updateEmailAddress(e) { 
    this.setState({ _emailAddress: e.target.value }); 
    } 

    handleSubmit() { 
    console.log(this.state._emailAddress); 
    } 

    render() { 
    return (
     <form onSubmit={this.handleSubmit}> 
     <input 
      value={this.state._emailAddress} 
      onChange={this.updateEmailAddress} 
     /> 
     </form> 
    ); 
    } 
} 
+0

Присвоение состояния становится немного грубым, когда формы становятся длинными, поэтому я пытался решить это с помощью 'ref'. Я полностью покупаю то, что я пытаюсь сделать, здесь невозможно, но не могли бы вы объяснить или ссылаться на статью, объясняющую, почему использование 'ref' - плохая идея в целом? – drewwyatt

+0

Возможно, вы могли бы составить свой компонент на нескольких уровнях? Задайте этот вопрос: https://stackoverflow.com/questions/29503213/use-state-or-refs-in-react-js-form-components –

+1

Здесь есть предостережение: https://facebook.github.io /react/docs/refs-and-the-dom.html#dont-overuse-refs –

2

мне нужно было что-то похожее на это. Чтобы добавить к ответу Брэда, вы можете передать обработчик проверки в качестве опоры, а затем использовать внутреннюю функцию для вызова обработчика проверки.

function CustomTextInput({ validationHandler }) { 
    // textInput must be declared here so the ref callback can refer to it 
    let textInput = null; 

    function handleClick() { 
    validationHandler(textInput.value); 
    } 

    return (
    <div> 
     <input 
     type="text" 
     ref={(input) => { textInput = input; }} /> 
     <input 
     type="button" 
     value="Validate the text input from a parent function" 
     onClick={handleClick} 
     /> 
    </div> 
); 
}