Как я могу привязать к компоненту refact в статусе без гражданства?

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

В моем примере ниже я _emailAddress с проблемой, когда входной ref никогда не назначается родительскому частному свойству _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>
);

Ответ 1

РЕДАКТИРОВАТЬ: Теперь вы можете с React Hooks. Смотрите ответ Анте Гулина.

Вы не можете получить доступ к React-подобным методам (например, componentDidMount, componentWillReceiveProps и т.д.) Для компонентов без состояний, включая refs. Проверьте это обсуждение на GH для полного convo.

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

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

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

Из документов...

Вы не можете использовать атрибут ref на функциональных компонентах, потому что у них нет экземпляров. Однако вы можете использовать атрибут 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>
  );  
}

Ответ 2

Вы можете использовать useRef которая доступна начиная с v16.7.0-alpha.

РЕДАКТИРОВАТЬ: Вам предлагается использовать Hooks в производстве 16.8.0 версии 16.8.0 !

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

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // 'current' points to the mounted text input element
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

Подробнее читайте в документации по Hooks API

Ответ 3

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

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>
  );  
}

Ответ 4

Значение вашего 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>
    );
  }
}