https://codesandbox.io/s/react-textarea-callback-on-blur-yoh8n?file=/src/App.tsx

प्रतिक्रिया में एक textarea होने के कारण मैं दो बुनियादी उपयोग के मामलों को प्राप्त करना चाहता हूं:

  1. जब उपयोगकर्ता "एस्केप" दबाता है तो फ़ोकस निकालें और कुछ स्थिति रीसेट करें
  2. कॉलबैक निष्पादित करें (saveToDatabase) जब उपयोगकर्ता टेक्स्ट क्षेत्र के बाहर क्लिक करता है और यह फोकस खो देता है (=> onBlur)
<textarea
  ref={areaRef}
  value={input}
  onChange={handleChange}
  onKeyDown={handleKeyDown}
  onBlur={handleBlur}
/>

पहले उपयोग के मामले में मैं लक्ष्य पर blur() को कॉल कर रहा हूं:

const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
  if (e.key === "Escape") {
    console.log("Escape clicked");
    setInput(inputForReset);
    e.currentTarget.blur();
  }
};

..लेकिन यह onBlur हैंडलर को भी कॉल करता है, जिसे मैं वास्तव में दूसरे उपयोग के मामले के लिए उपयोग करना चाहता हूं। मैंने यह निर्धारित करने का प्रयास किया कि ईवेंट कॉलर टेक्स्टरेरा स्वयं एक रेफरी के माध्यम से है, लेकिन यह काम नहीं करता है:

const handleBlur = (e: React.FocusEvent<HTMLTextAreaElement>) => {
  console.log("blur");
  /**
   * Only save to database when losing focus through clicking
   * outside of the text area, not for every blur event.
   */
  if (areaRef.current && !areaRef.current.contains(e.currentTarget as Node)) {
    saveToDatabase();
  }
};

दूसरे शब्दों में: जब उपयोगकर्ता टेक्स्टरेरा में संपादन समाप्त कर लेता है, तो मैं डेटाबेस में कुछ सहेजना चाहता हूं, लेकिन मुझे नहीं पता कि blur ईवेंट के बीच अंतर कैसे करें, मैंने प्रोग्रामेटिक रूप से ट्रिगर किया और मूल blur जब आप नोड के बाहर क्लिक करते हैं तो टेक्स्टरेरा उपयोग करता है।

1
Bennett Dams 2 सितंबर 2020, 16:34

2 जवाब

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

मैंने देखा कि त्रुटि क्या है। ब्लर इवेंट का टारगेट खुद होता है

areaRef === event.target

तो आपको बॉक्स के बाहर क्लिक पकड़ने के लिए एक अतिरिक्त फ़ंक्शन लागू करना होगा।

import * as React from "react";
import "./styles.css";
import { useState, useRef, useEffect } from "react";

function useOutsideAlerter(
  ref: React.RefObject<HTMLTextAreaElement>,
  fun: () => void
) {
  useEffect(() => {
    function handleClickOutside(event: any) {
      if (
        ref.current &&
        !ref.current.contains(event.target) &&
        // THIS IS IMPORTANT TO CHECK
        document.activeElement === ref.current
      ) {
        fun();
      }
    }

    // Bind the event listener
    document.addEventListener("mousedown", handleClickOutside);
    return () => {
      // Unbind the event listener on clean up
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [ref]);
}

export default function App() {
  const areaRef = useRef<HTMLTextAreaElement>(null);
  const [inputForReset, setInputForReset] = useState<string>("Original input");
  const [input, setInput] = useState<string>(inputForReset);

  const saveToDatabase = () => {
    console.log("save to database");
    setInputForReset(input);
    alert(input);
  };

  // OUT SIDE CLICK

  useOutsideAlerter(areaRef, saveToDatabase);

  const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
    setInput(e.target.value);
  };

  const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
    if (e.key === "Escape") {
      console.log("Escape clicked");
      setInput(inputForReset);
      e.currentTarget.blur();
      e.stopPropagation();
    }
  };

  // it doesnt work
  
  const handleBlur = (e: React.FocusEvent<HTMLTextAreaElement>) => {
    /**
     * Only save to database when losing focus through clicking
     * outside of the text area, not for every blur event.
     */
    console.log(event.target);
    console.log(areaRef);

    if (areaRef.current && !areaRef.current.contains(event.target)) {
      saveToDatabase();
    }
  };

  return (
    <div className="App">
      <textarea
        ref={areaRef}
        value={input}
        onChange={handleChange}
        onKeyDown={handleKeyDown}
        onBlur={handleBlur}
        className="area"
      />
      <p>Input state: {input}</p>
    </div>
  );
}

कृपया मेरा sandbox

1
Piotr Pieprzyk 2 सितंबर 2020, 17:38

हो सकता है कि आप "preventsaveOnBlur" ध्वज के रूप में एक चर (या एक वर्ग संपत्ति, यदि आप एक कार्यात्मक के बजाय वर्ग घटक का उपयोग कर रहे हैं) जोड़ सकते हैं; कुछ इस तरह:

let preventSaveOnBlur: boolean = false;

const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
  if (e.key === "Escape") {
    console.log("Escape clicked");
    setInput(inputForReset);
    preventSaveOnBlur = true;  // will prevent saving on DB - see handleBlur 
    e.currentTarget.blur();
  }
};

const handleBlur = (e: React.FocusEvent<HTMLTextAreaElement>) => {
  console.log("blur");
  /**
   * Only save to database when losing focus through clicking
   * outside of the text area, not for every blur event.
   */
  if (!preventSaveOnBlur) {
    saveToDatabase();
  }
};

const handleFocus = (e: React.FocusEvent<HTMLTextAreaElement>) => {
  preventSaveOnBlur = false;
};

और टेक्स्टरेरा में आप ऑनफोकस ईवेंट भी संभालते हैं:

<textarea
  ref={areaRef}
  value={input}
  onChange={handleChange}
  onKeyDown={handleKeyDown}
  onBlur={handleBlur}
  onFocus={handleFocus} // will reset 'preventSaveOnBlur' to false every time the textarea get the focus
/> 
0
secan 2 सितंबर 2020, 17:38