Реакция: потери значений ref

Я использую два компонента, и я использую этот шаблон: дочерний компонент должен оставаться изолированным как можно больше - он обрабатывает собственную ошибку проверки. Родительский компонент должен проверять наличие ошибок, которые имеют зависимости между дочерними элементами. Итак, в моем случае: поле password и password confirmation.

Вот мой код:

a) SignUp (родительский)

Установка начального состояния.

 constructor() {
     super();

     this.state = {
         isPasswordMatching: false
     };
 }

В методе render() я выводил свой дочерний компонент. Через prop под названием callback Я распространяю метод isPasswordMatching(), связывая родительский this. Цель состоит в том, что метод может быть вызван в дочернем компоненте.

<TextInput
    id={'password'}
    ref={(ref) => this.password = ref}
    callback={this.isPasswordMatching.bind(this)}
    // some other unimportant props
/>

<TextInput
    id={'passwordConfirm'}
    ref={(ref) => this.passwordConfirm = ref}
    ...

isPasswordMatching() метод проверяет, соответствуют ли пароли (через refs this.password и this.passwordConfirm), а затем обновляется состояние. Обратите внимание, что этот метод вызывается внутри дочернего элемента (пароль или парольConfirm).

isPasswordMatching() {
    this.setState({
        isPasswordMatching: this.password.state.value === this.passwordConfirm.state.value
    });
}

b) TextInput (child)

Установка начального состояния.

constructor() {
    super();

    this.state = {
        value: '',
        isValid: false
    };
}

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

onBlur(event) {

    // doing validation and preparing error messages

    this.setState({
        value: value,
        isValid: this.error === null
    });
}

Последние. Вызывается обратный вызов.

componentDidUpdate(prevProps) {
    if (prevProps.id === 'password' || prevProps.id === 'passwordConfirm') {
        prevProps.callback();
    }
}

Вопрос

Как-то мои ссылки теряются. Сценарий:

  • Родительский компонент - это рендер
  • Реализованные дочерние компоненты
  • Я вхожу в одно из полей ввода и выхожу (это вызывает метод onBlur()) - состояние обновляется, дочерний компонент отображается
  • componentDidUpdate() вызывается и prevProp.callback() также
  • При переходе к методу isPasswordMatching() я выводя this.password и this.passwordConfirm - это объекты с ожидаемыми значениями ссылки. Обновляется состояние родительского компонента.
  • Затем снова воспроизводятся все дети, компоненты обновляются, вызывается callback, но на этот раз this.password и this.passwordConfirm находятся null.

Я понятия не имею, почему ссылки потеряны. Должен ли я делать что-то по-другому? Заранее благодарю вас.

Ответ 1

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

Обратите внимание, что когда ссылочный компонент размонтируется и всякий раз, когда ref изменяется, старый ref будет вызываться с нулевым аргументом. Это предотвращает утечку памяти в том случае, если экземпляр хранится, как во втором примере. Также обратите внимание, что при написании ссылок с встроенными функциональными выражениями, как в приведенных здесь примерах, React видит каждый объект-объект каждый раз, поэтому при каждом обновлении ref будет вызываться с нулевым значением непосредственно перед вызовом с экземпляром компонента.

Ответ 2

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

https://reactjs.org/docs/refs-and-the-dom.html#refs-and-functional-components

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

В документации объясняется, что вы должны сделать, чтобы решить проблему, если у вас есть контроль над компонентом, который вы пытаетесь выполнить.

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

В

<div ref={element => this.elementName = element}>
    <FunctionalComponent />
</div>

Не работает
устанавливает this.elementName на null

<FunctionalComponent ref={element => this.elementName = element} />

Надеюсь, это поможет любому, кто найдет этот вопрос, как я.