@ceeed

Когда я хочу сменить значение в инпуте, то курсор после удаления первого элемента прыгает в конец, как отменить такое поведение после смены значения?

Мне нужно чтобы после удаления первого символа - я мог дальше спокойно редактировать инпут с этого же места. Вот как сейчас это работает..
62a9a270466c6774893257.gif

Родительский компонент:

Сам элемент в разметки:

<LimChanger
                    loading={loadingSendLims}
                    onChange={this.changeHandler}
                    cantEdit={messageTextLims}
                    cancel={this.cancelChangeLims}
                    send={this.sendLims}
                    message={messageTextLims}
                    changed={(currentMaxLimChange !== null && currentMaxLimChange !== String(offer.maxAmount))
                      || (currentMinLimChange !== null && currentMinLimChange !== String(offer.minAmount))}
                    minLim={currentMinLimChange !== null ? currentMinLimChange : offer.minAmount}
                    maxLim={this.state.maxLimInput}
                  />


Функция которая передается в onChange
changeHandler = (e): void => {
    const {value} = e.target;
    const num = Number(value);
    const isValid = !isNaN(num);
    // что-то делаем с валидным / невалидным
    if (isValid) {
    // @ts-ignore
      this.setState({[e.target.name]: value});
    } else {
      console.log('invalid');
    }
  }


Функция которая передается в cancel

cancelChangeLims = (): void => {
    this.setState({
      currentMinLimChange: null,
      maxLimInput: 0,
    });
  }


Функция которая передается в send
sendLims = (): void => {
    const {currentMinLimChange, maxLimInput} = this.state;
    const {offer, t} = this.props;
    this.setState({loadingSendLims: true});
    const prevMinLim = offer.minAmount;
    const prevMaxLim = offer.maxAmount;
    const newMinLim = parseFloat(String(currentMinLimChange));
    const newMaxLim = parseFloat(String(maxLimInput));
    const sendObj: Record<string, number | string | boolean> = {};
    if (prevMinLim !== newMinLim && newMinLim) sendObj.minAmount = newMinLim;
    else sendObj.minAmount = prevMinLim;
    if (prevMaxLim !== newMaxLim && newMaxLim) sendObj.maxAmount = newMaxLim;
    else sendObj.maxAmount = prevMaxLim;

    if (sendObj.maxAmount <= sendObj.minAmount) {
      this.setState({
        currentMinLimChange: null,
        maxLimInput: 0,
        messageTextLims: t('oneOffer.limitsValidationErrorMessage'),
      }, () => {
        setTimeout(() => {this.setState({messageTextLims: ''});}, 2400);
      });
      return;
    }

    const errorCallback = (e?: Error): void => {
      this.setState({
        currentMinLimChange: null,
        maxLimInput: 0,
        loadingSendLims: false,
        messageTextLims: t('common.error'),
      });
      setTimeout(() => {
        this.setState({messageTextLims: ''});
      }, 1800);

      if (e) {
        this.props.setError?.(e.toString());
        throw e;
      }
    };

    putData (`/api/postings/${offer.exchange}/${offer.id}/settings/exchange`, sendObj).then(response => {
      if (response.success) {
        this.setState({
          currentMinLimChange: null,
          maxLimInput: 0,
          loadingSendLims: false,
          messageTextLims: t('oneOffer.limitsUpdated'),
        }, () => {
          setTimeout(() => {this.setState({messageTextLims: ''});}, 1800);
          if (prevMinLim !== newMinLim && newMinLim) this.props.updateOfferExchangeData?.(offer.id, 'minAmount', newMinLim);
          if (prevMaxLim !== newMaxLim && newMaxLim) this.props.updateOfferExchangeData?.(offer.id, 'maxAmount', newMaxLim);
          this.prepareData();
        });

        return;
      }

      if (response.error) {
        this.props.setError?.(response.error);
      }
      errorCallback();
    }).catch(errorCallback);
  }


Сам инпут в дочернем компоненте

<input
            autoComplete="off"
            className="classic_input limit_changer_input"
            onKeyDown={this.handleKeyDown}
            ref={ref => this.ref = ref}
            name="maxLimInput"
            onChange={e => this.props.onChange(e, this.ref)}
            placeholder={this.props.placeholder || ''}
            value={this.state.maxLim}
          />


Как мне сделать нормальное поведение инпута, без перескакивания в начало?
  • Вопрос задан
  • 552 просмотра
Пригласить эксперта
Ответы на вопрос 1
@strelok011
Основная проблема - ререндер компонента с промежуточной обработкой значения реактом.
Это не ошибка а ожидаемое поведение реакта, он теряет позицию курсора.
Можно посмотреть к примеру здесь как разработчики борются с таким поведением.
Общая идея - обрабатывать в onChange еще и положение курсора, сохранять его в стейте и использовать при ререндере.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы