React: الخطأ: تحديث حالة غير ذي صلة في كتل onKeyDown عند التغيير وكسر المكون المتحكم فيه

تم إنشاؤها على ٩ يوليو ٢٠٢٠  ·  3تعليقات  ·  مصدر: facebook/react

مرحبًا ، أستخدم وضع التحكم في الإدخال واشترك في حدث onKeyDown و onChange . سيطلق تأثير عندما يدخل المستخدم الفضاء. ومع ذلك ، لا يتم عرض المساحة على الشاشة. هل هذا خطأ في React أم أن هناك خطأ ما في طريقة استخدامه. لكن الاشتراك في onKeyUp أمر عادي. هذا مشوش.

إصدار React: 16.13.1 والقديم

خطوات التكاثر

  1. أدخل الفضاء
  2. لا يُظهر عنصر الإدخال مساحة على الشاشة

رابط لمثال التعليمات البرمجية:

import React, { useState,useEffect } from 'react'

const App = () => {
  const [count, setCount] = useState(0)
  const [value, setValue] = useState('')
  const [code, setCode] = useState('add')

  useEffect(() => {
    if (code === 'add') {
      setCount(c => c + 1)
    } else {
      setCount(c => c - 1)
    }
  }, [code, setCount])

  const keyDown = e => {
    if (e.keyCode === 32) {
      console.log('space~')
      if (code === 'add') {
        setCode('minus')
      } else {
        setCode('add')
      }
    }
  }

  const handleChange = e => {
    setValue(e.target.value)
  }

  return (
    <div>
      <div>{count}</div>
      <br />
      <input onKeyDown={keyDown} value={value} onChange={handleChange} />
    </div>
  )
}

export default App

السلوك الحالي

لا يمكن لعنصر الإدخال تلقي المسافة

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

يمكن أن يتلقى عنصر الإدخال المساحة

DOM Unconfirmed Bug

ال 3 كومينتر

يبدو أن تحديث الحالة في معالج onKeyDown يقاطع الحدث ويمنع استدعاء المعالج onChange . نظرًا لأن المكونات التي يتم التحكم فيها تظهر فقط ما تخبرهم به (الحالة value في مثالك) ، ينتج عن ذلك عدم ظهور حرف المسافة مطلقًا.

هذا يبدو لي وكأنه خطأ في الطريقة التي يتفاعل بها هذان الحدثان.

cctrueadmgaearon لخبرتهم في نظام الأحداث

مرحبًا ، أنا جديد هنا ، أحاول تعلم هندسة React.

bvaughn هذا شيء وجدته حول المشكلة.

onKeyDown event لا يحظر onChange بدلاً من أن يتم تشغيله قبل تعديل الإدخال. بشكل أساسي ، ينتقل onKeyDown قبل onChange لأن إدخال النص يحدث في onKeyUp .

في هذه الحالة بالذات ، تكمن المشكلة في أنه في حدود keyDown ، عندما يكون setCode مكالمات ، في أول dispatchAction _Fiber_ memoizedState بدون الحرف الجديد (من الواضح) و e التي ستتم إضافتها. في النهاية ، يضيف الحرف الجديد إلى المدخلات. ثم يقوم useEffect() بتشغيل dispatchAction مرة أخرى داخل _ نفس قائمة الانتظار_ (لست متأكدًا مما إذا كانت قائمة الانتظار) ولكنها لا تعرف أي شيء عن الدعائم المحدثة. نتيجة لذلك ، عندما يكون commitRoot ، فإنه يستعيد pendingProps وهو نفسه كما كان في memoizedState . باختصار ، تتم إضافة الحرف (مسافة في هذا المثال) ثم يتم استعادة الحالة القديمة على الفور بدون الحرف الجديد (مسافة) ، لذلك يبدو أنه لا يضيف أي شيء.

كمثال على عدم استخدام _same queue_ (؟) ، هذا المثال بالذات:

useEffect(() => {
    if (code === 'add') {
      setCount(c => c + 1)
    } else {
      setCount(c => c - 1)
    }
  }, [code, setCount])

يمكن تعديله إلى:

useEffect(() => {
    if (code === 'add') {
      setTimeout(() => setCount(c => c + 1), 0)
    } else {
      setTimeout(() => setCount(c => c - 1), 0)
    }
  }, [code, setCount])

وسيعمل.

آمل أنه من المنطقي.

ركضت في نفس المشكلة ، وقمت بإصلاح استدعاء setState الخاص بي في aa setTimeout في معالج keydown.

لدي فضول لمعرفة ما إذا كان هذا شيء يجب أن يعمل بشكل مختلف تحت غطاء المحرك في React أو إذا كان هذا الخطأ يشير إلى خطأ أكبر أو نمط سيئ من جانب المطور؟

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