هل تريد طلب ميزة أو الإبلاغ عن خطأ ؟
خلل برمجي!
ما هو السلوك الحالي؟
عند عرض عنصر input
من النوع checkbox
باستخدام معالج onClick
و onChange
، لا يزال يتم استدعاء onChange
على الرغم من event.preventDefault()
يسمى في onClick
المعالج.
إذا كان السلوك الحالي عبارة عن خطأ ، فيرجى تقديم خطوات إعادة الإنتاج وإذا أمكن عرضًا توضيحيًا بسيطًا للمشكلة عبر https://jsfiddle.net أو ما شابه (نموذج: https://jsfiddle.net/reactjs/69z2wepo/).
ما هو السلوك المتوقع؟
استدعاء event.preventDefault
في المعالج onClick
يمنع حدوث الإجراء الافتراضي (أو التراجع عن تأثيره) ، وهو تحديث قيمة العنصر input
. يجب أن يؤدي هذا إلى إيقاف استدعاء أي مستمع حدث change
. راجع https://jsfiddle.net/L1eskzsq/ لمعرفة السلوك المتوقع
ما إصدارات React وأي متصفح / نظام تشغيل متأثر بهذه المشكلة؟
تم اختباره باستخدام إصدار من Master ، macOS 10.12.2 ، تم التحقق منه في:
يستدعي Safari 10.0.2 مستمع الحدث change
في كلتا الحالتين.
يتم إنشاء الحدث 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;
}
}
التعليق الأكثر فائدة
هل هذا مرتبط؟
preventDefault
استدعاءonChange
يتسبب في خروج React وحالة المتصفح عن المزامنة: https://codesandbox.io/s/0qpr936xkv