React: لا يمنع event.preventDefault في معالج النقر استدعاء onChange

تم إنشاؤها على ١٧ فبراير ٢٠١٧  ·  6تعليقات  ·  مصدر: facebook/react

هل تريد طلب ميزة أو الإبلاغ عن خطأ ؟

خلل برمجي!

ما هو السلوك الحالي؟

عند عرض عنصر input من النوع checkbox باستخدام معالج onClick و onChange ، لا يزال يتم استدعاء onChange على الرغم من event.preventDefault() يسمى في onClick المعالج.

إذا كان السلوك الحالي عبارة عن خطأ ، فيرجى تقديم خطوات إعادة الإنتاج وإذا أمكن عرضًا توضيحيًا بسيطًا للمشكلة عبر https://jsfiddle.net أو ما شابه (نموذج: https://jsfiddle.net/reactjs/69z2wepo/).

http://jsfiddle.net/rf3w7apc/

ما هو السلوك المتوقع؟

استدعاء event.preventDefault في المعالج onClick يمنع حدوث الإجراء الافتراضي (أو التراجع عن تأثيره) ، وهو تحديث قيمة العنصر input . يجب أن يؤدي هذا إلى إيقاف استدعاء أي مستمع حدث change . راجع https://jsfiddle.net/L1eskzsq/ لمعرفة السلوك المتوقع

ما إصدارات React وأي متصفح / نظام تشغيل متأثر بهذه المشكلة؟

تم اختباره باستخدام إصدار من Master ، macOS 10.12.2 ، تم التحقق منه في:

  • Chrome 56.0.2924.87 (64 بت)
  • Firefox 51.0.1 (64 بت)

يستدعي Safari 10.0.2 مستمع الحدث change في كلتا الحالتين.

DOM Bug

التعليق الأكثر فائدة

هل هذا مرتبط؟ preventDefault استدعاء onChange يتسبب في خروج React وحالة المتصفح عن المزامنة: https://codesandbox.io/s/0qpr936xkv

ال 6 كومينتر

يتم إنشاء الحدث change بواسطة ChangeEventPlugin كاستجابة لـ topChange ، قبل حتى أن يتم استدعاء معالج onClick (لذلك قبل preventDefault call) ، هنا: https://github.com/facebook/react/blob/master/src/renderers/dom/shared/eventPlugins/ChangeEventPlugin.js#L338

يحاول هذا المكون الإضافي معرفة ما إذا كانت قيمة مربع الاختيار ستتغير أم لا ، وإذا كانت الإجابة بنعم ، فسيصنف الحدث change في قائمة الانتظار. يستخدم وظيفة inputValueTracking لمقارنة القيمة السابقة بالقيمة التالية لاتخاذ هذا القرار ، هنا: https://github.com/facebook/react/blob/master/src/renderers/dom/shared/ inputValueTracking.js # L154

يتم أخذ nextValue مباشرة من DOM كما يلي: value = isCheckable(node) ? '' + node.checked : node.value; https://github.com/facebook/react/blob/master/src/renderers/dom/shared/inputValueTracking.js# L56

المشكلة هي أن قيمة node.checked صحيحة مؤقتًا في هذه المرحلة ، لذلك بعد النقرة الأولى تكون:

lastValue == false (صحيح)
nextValue == true (غير صحيح)

وفي النقرة التالية على مربع الاختيار ، لم يعد يتم تشغيل الحدث change ، لأن القيم هي:

lastValue == true (غير صحيح)
nextValue == true (غير صحيح)

بشكل عام ، يبدو أن المشكلة هي أن React تسأل DOM عن قيمة checked للعقدة ، قبل أن يُستدعى منع PreventionDefault في onClick .

شكرًا karelskopek و Mintaffee على مساعدتك في البحث في هذا الأمر.

aweary هل تعتقد أن هذا يستحق الحل؟

لا يوجد تقدم مع هذا؟ أنا أستخدم React v16.2 والسلوك هو نفسه - يتم تشغيل onChange لأول مرة ولا تؤدي النقرات اللاحقة إلى تشغيله. أود أن أقول مسألة ذات أولوية عالية هنا ..

هل هذا مرتبط؟ preventDefault استدعاء onChange يتسبب في خروج React وحالة المتصفح عن المزامنة: https://codesandbox.io/s/0qpr936xkv

لا تزال مشكلة في React 16.8.6. أحد الحلول الممكنة هو القيام بكل شيء في معالج onClick :

const radios = ['one', 'two', 'three'];

class Row extends Component {
  constructor(props) {
    super(props);
    this.onClick = this.onClick.bind(this);
    this.onChange = this.onChange.bind(this);
  }

  render() {
    const { value } = this.props;
    return (
      <div className="row">
        <div className="radio-group">
          {radios.map(radio => (
            <label key={radio} className="radio">
              <input
                type="radio"
                name="radio"
                value={radio}
                checked={radio === value}
                onClick={this.onClick}
                onChange={this.onChange}
              /><span>Radio</span>
            </label>
          ))}
        </div>
      </div>
    );
  }

  onClick(event) {
    // Check something to prevent radio change
    if (...) {
      event.preventDefault();
      return;
    }
    // Sync value in the store
    this.props.setValue(event.target.value);
  }
  onChange() {
    // We need this empty handler to suppress React warning:
    // "You provided a `checked` prop to a form field without an `onChange` handler.
    // This will render a read-only field. If the field should be mutable use `defaultChecked`.
    // Otherwise, set either `onChange` or `readOnly`"
  }
}

إذا كنت تستخدم مكونًا خاضعًا للرقابة ، فإن خيارًا آخر وجدته هو ترك القيمة في الحالة دون تغيير:

onChange(event) {
  // Check something to prevent radio change
  if (...) {
    return;
  }
  // Sync value in the store
  this.props.setDateTime(event.target.value);
}

للحصول على حل أبسط ، يمكنك فعل e.preventDefault على حدث onMouseDown لمنع onChange من إطلاق.

onMouseDown(e) { if (...) { e.preventDefault(); return; } }

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات