मैं इस त्रुटि पर लंबे समय से अटका हुआ हूं, इसलिए मैं कुछ मदद की सराहना करता हूं। यहाँ एक न्यूनतम प्रतिलिपि प्रस्तुत करने योग्य उदाहरण है:

import "./App.css";
import React, { useState } from "react";
import $ from "jquery";

function App() {
    const [value, setValue] = useState("");

    const focusHandler = () => {
        $("input").on("keypress", (e) => {
            let copy = value;
            if (e.key === ".") {
                e.preventDefault();
                copy += "    ";
                setValue(copy);
            }
        });
    };

    const blurHandler = (event) => {
        $("input").off("keypress");
        setValue(event.target.value);
    };

    const changeHandler = (event) => {
        setValue(event.target.value);
    };

    return (
        <div>
            <input
                value={value}
                onFocus={focusHandler}
                onBlur={blurHandler}
                onChange={changeHandler}
            />
        </div>
    );
}

export default App;

इनपुट फोकस पर, मैं एक . कीप्रेस देखने के लिए एक ईवेंट श्रोता जोड़ रहा हूं और इनपुट में एक टैब (4 रिक्त स्थान) जोड़ रहा हूं यदि इसे दबाया जाता है। लेकिन जब मैं कई बार . दबाता हूं, तो इनपुट पहले टैब पर अटक जाता है, और आगे नहीं बढ़ता (जैसे इनपुट स्थायी रूप से 4 रिक्त स्थान दिखाता है)। console.log का उपयोग करने से मुझे पता चलता है कि value स्थिति focusHandler में अपडेट नहीं हो रही है और मूल मान ("") पर वापस आ जाती है।

एक महत्वपूर्ण नोट यह है कि this.state के साथ वर्ग-आधारित घटक पर स्विच करने से यह काम करता है। ऐसा क्यों हो रहा है इस पर कोई अंतर्दृष्टि?

1
Sam Liu 8 जुलाई 2021, 17:47

2 जवाब

सबसे बढ़िया उत्तर

रिएक्ट के साथ डायरेक्ट डोम मैनिपुलेशन को मिक्स न करें, चाहे वह वैनिला जावास्क्रिप्ट हो या jQuery। यहां jQuery के साथ ईवेंट हैंडलर जोड़ने की कोई आवश्यकता नहीं है, क्योंकि आपके तरीके पहले से ही ईवेंट हैंडलर हैं। बस उन्हें सीधे इस्तेमाल करें:

    const focusHandler = (e) => {
        // handle the event here!
    }
1
Code-Apprentice 8 जुलाई 2021, 15:25

जैसा कि टिप्पणियों में बताया गया है, jQuery कार्य के लिए गलत टूल है। JQuery में लाना सीधे DOM विधियों को कॉल करने के समान है: यह रिएक्ट को दरकिनार कर रहा है और उन लोगों के ऊपर अतिरिक्त श्रोता जोड़ रहा है जो रिएक्ट आपको पहले से ही देता है। यदि आप प्रतिक्रिया से असंबंधित कई हैंडलर से स्थिति निर्धारित कर रहे हैं तो आप दुर्व्यवहार की उम्मीद कर सकते हैं। एक बार जब आप रिएक्ट में हों, तो समस्या को हल करने के लिए उन उपकरणों का उपयोग करें जो आपको (रेफरी, प्रभाव, हैंडलर) देता है।

सबसे खराब स्थिति तब होती है जब एक दृष्टिकोण काम करने के लिए प्रकट होता है, फिर उत्पादन में विफल रहता है, अन्य लोगों की मशीनों/ब्राउज़रों पर, जब कक्षाओं से हुक या इसके विपरीत, रिएक्ट के विभिन्न संस्करणों में, या 1 के लिए रिफैक्टरिंग करते हैं 1000 उपयोगकर्ताओं में से। एपीआई रिएक्ट के भीतर अच्छी तरह से रहना आपको बेहतर गारंटी देता है कि आपका ऐप सही तरीके से व्यवहार करेगा।

नियंत्रित घटक

इनपुट मान में हेरफेर करने के लिए, आप दोनों onKeyDown और onChange श्रोताओं का उपयोग कर सकते हैं। onKeyDown पहले फायर करता है। onKeyDown के अंदर event.preventDefault() को कॉल करने से परिवर्तन घटना अवरुद्ध हो जाएगी और यह सुनिश्चित करेगी कि setState पर नियंत्रित इनपुट मान प्रति कीस्ट्रोक के लिए केवल एक कॉल हो।

इसके साथ समस्या इनपुट कर्सर घटक के बाद अंत तक चला जाता है अपडेट (प्रासंगिक GitHub समस्या देखें)। इससे निपटने का एक तरीका यह है कि जब आप कर्सर का ट्रैक रखने के लिए राज्य जोड़कर स्ट्रिंग में आक्रामक परिवर्तन करते हैं तो कर्सर की स्थिति को मैन्युअल रूप से समायोजित करें और selectionStart सेट करने के लिए रेफरी और useEffect का उपयोग करें। और selectionEnd इनपुट तत्व पर गुण।

यह एक संक्षिप्त ब्लिंकिंग प्रभाव का कारण बनता है, जो रेंडर के बाद अतुल्यकालिकता के कारण होता है, इसलिए यह एक अच्छा समाधान नहीं है। यदि आप हमेशा मूल्य के अंत में जोड़ रहे हैं, तो आप मानते हैं कि उपयोगकर्ता कर्सर को अन्य उत्तरों के रूप में नहीं ले जाएगा, या आप कर्सर को अंत में समाप्त करना चाहते हैं, तो यह एक गैर-मुद्दा है, लेकिन यह धारणा सामान्य मामले में नहीं है। घटक को नियंत्रित रखते हुए मैं एक बेहतर समाधान देखने के लिए उत्सुक हूं।

const {useEffect, useRef, useState} = React;

const App = () => {
  const [value, setValue] = useState("");
  const [cursor, setCursor] = useState(-1);
  const inputRef = useRef();
  const pad = ".    ";
  
  const onKeyDown = event => {
    if (event.code === "Period") {
      event.preventDefault();
      const {selectionStart: start} = event.target;
      const {selectionEnd: end} = event.target;
      const v = value.slice(0, start) + pad + value.slice(end);
      setValue(v);
      setCursor(start + pad.length);
    }
  };
  
  const onChange = event => {
    setValue(event.target.value);
    setCursor(-1);
  };
  
  useEffect(() => {
    if (cursor >= 0) {
      inputRef.current.selectionStart = cursor;
      inputRef.current.selectionEnd = cursor;
    }
  }, [cursor]);

  return (
    <div>
      <p>press `.` to add 4 spaces:</p>
      <input
        ref={inputRef}
        value={value}
        onChange={onChange}
        onKeyDown={onKeyDown}
      />
    </div>
  );
};

ReactDOM.render(<App />, document.body);
input {
  width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>

अनियंत्रित घटक

यहाँ एक अनियंत्रित घटक का उपयोग करने का एक और प्रयास है। इसमें ब्लिंकिंग की समस्या नहीं है क्योंकि DOM एलिमेंट की .value प्रॉपर्टी को उसी समय .selectionStart प्रॉपर्टी के साथ सिंक्रोनाइज़ किया जाता है और उसी रिपेंट पर दिखाई देता है।

const App = () => {
  const pad = ".    ";
  
  const onKeyDown = event => {
    if (event.code === "Period") {
      event.preventDefault();
      const {target} = event;
      const {
        value, selectionStart: start, selectionEnd: end,
      } = target;
      target.value = value.slice(0, start) + 
                     pad + value.slice(end);
      target.selectionStart = start + pad.length;
      target.selectionEnd = start + pad.length;
    }
  };

  return (
    <div>
      <p>press `.` to add 4 spaces:</p>
      <input
        onKeyDown={onKeyDown}
      />
    </div>
  );
};

ReactDOM.render(<App />, document.body);
input {
  width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
1
ggorlen 8 जुलाई 2021, 18:59