Синхронизируйте состояние React с коллекцией Meteor, используя debounce

У меня есть текстовое поле в моем приложении Meteor + React. Я хочу синхронизировать его значение с коллекцией Mongo. Однако я не хочу обновлять коллекцию после каждого нажатия клавиши, только когда пользователь перестал печатать на несколько секунд.

Текстовое поле в моей функции render() выглядит так:

<input type="text" ref="answer" onChange={this.onChange} value={this.state.someValue} />

Я сохраняю значение текстового поля в this.state вместо this.data, потому что this.data отражает коллекцию Mongo, которая, возможно, еще не была обновлена.

Пока все это работает.

Проблема:

Если другой клиент обновляет коллекцию, я хочу, чтобы в текстовом поле отображалось обновленное значение. Для этого мне нужно обновить this.state внутри функции getMeteorData(), но это запрещено, и я получаю сообщение об ошибке: "Вызов setState внутри getMeteorData может привести к бесконечному циклу".

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

Есть лучший способ сделать это? Могу ли я принудительно обновить состояние внутри getMeteorData(), если я пообещаю, что буду хорошим мальчиком и буду вести себя хорошо?


person aedm    schedule 06.11.2015    source источник


Ответы (1)


Я бы вообще избавился от getMeteorData и обратился бы к createContainer. Поток данных становится ясным и простым большую часть времени, включая этот конкретный случай. Вот оно.

Прежде всего, создайте контейнер для извлечения данных.

export default theContainer = createContainer(() => {
  // Subscribe to the publication which publishes the data.
  const subscription = Meteor.subscribe(...);
  // Derive the data for the input box and form the props to pass down.
  const props = {
    answer: getAnswer(subscription)
  };
  return props;
}, theComponent);

theContainer действует как компонент-контейнер и передает содержащиеся данные в презентационный компонент theComponent с помощью реквизита. Обратите внимание, что функция, назначенная createContainer, является адаптивной, а это означает, что изменения в реактивных источниках данных в этой функции вызывают повторный запуск и приводят к повторному рендерингу theComponent.

К настоящему времени мы все вооружены. Поскольку данные в коллекции Mongo (точнее, Minimongo) синхронизируются передаваемыми реквизитами, theComponent знает о синхронизации переходом реквизита.

export default class theComponent extends React.Component {
  ...

  componentWillReceiveProps(nextProps) {
    if (this.props.answer !== nextProps.answer) {
      this.setState({
        answer: nextProps.answer
      });
    }
  }

  render() {
    return <input value={this.state.answer} onChange={this.onChange} />;
  }
}

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

С другой стороны, когда пользователь начинает печатать, обработчик изменений this.onChange обновляет ввод пользователя до состояния с каждым нажатием клавиши, поскольку это контролируемый компонент. Однако обработчик обновляет коллекцию Mongo (опять же точно Minimongo) только по истечении заданного времени для сохранения передачи данных.

person Season    schedule 09.07.2016