Home > Mobile >  event problem using addEventListener in a React functional component
event problem using addEventListener in a React functional component

Time:07-18

I have an input in a React component. I'm looking to add a character autocompletion feature. If the user enters " or ' a second identical character is added and the mouse cursor is put between the two new quotes created.

I had asked a question about how to make this component in React that I managed to solve myself: first SO question

To do this I used a suite of useEffects that reprocess the user's input each time a new character is entered. This causes performance problems and strange bugs because, I think, the state variables do not have time to update in my component.

So I want to change my current implementation that uses multiple React useEffect hooks to a vanilla JS implementation triggered by a single useEffect in my component.

But I have never used vanilla JS directly in a React component, is this something that can be done and is considered a good practice in React or can it bring unwanted behaviors?

To rewrite my component with vanillla JS I rewrote the following component:

(I tried to simplify my component but it is normally reproducible)

import * as React from "react";
import { useEffect, useState, useRef } from "react";
 
const QuoteInput: React.FC = () => {
 
    const inputRef = useRef<HTMLInputElement | null>(null);
 
    const [inputChoose, setInputChoose] = useState("");

    const [testQuoteAddition, setTestQuoteAddition] = useState(false);
 
    const inputHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
        const enteredRequest = event.target.value;
        setRequestChoose(enteredRequest);
 
        setTestQuoteAddition(true);
    };

    const handleComplete = (event: KeyboardEvent) => {
        if((event.key === "'" || event.key === '"') && (-1 !== ["'", "\""].indexOf(event.key))) {
            let longueur = event.target?.value as HTMLInputElement; //ERROR ON PROPERTY 'value' -> Property 'value' does not exist on type 'EventTarget'.ts(2339)
            let position = event.target?.selectionStart; //ERROR ON PROPERTY 'selectionStart' -> Property 'selectionStart' does not exist on type 'EventTarget'.ts(2339)
        
            event.target?.value = event.target?.value.substr(0, position)   event.key   event.target?.value.substr(position, longueur); //ERROR: The left-hand side of an assignment expression may not be an optional property access.ts(2779)
Property 'value' does not exist on type 'EventTarget'.ts(2339)
        
            event.target?.setSelectionRange(position, position);
        }

    };
    
    useEffect(() => {
        if (testQuoteAddition=== true) {
            inputRef.current?.addEventListener("keydown", e => {handleComplete(e)});
            
            // cleanup this component
            return () => {
                inputRef.current?.removeEventListener("keydown", e => {handleComplete(e)});
            };
        }
        setTestQuoteAddition(false);
    }, [testQuoteAddition]);
 
    return(
        <div>
            <input ref={inputRef} type="text" onChange={inputHandler} value={inputChoose} className="text-center" placeholder="enter an input" />
        </div>
    );
}
 
export default QuoteInput;

As for the inputHandler which takes as parameter an event of type React.ChangeEvent<HTMLInputElement>, it works well and updates the input entered by the user.

On the other hand for the handleComplete, the listener function of my addEventListener, which takes as parameter an event of type KeyboardEvent, I have several errors indicating me that the properties of the event to which I try to reach are not defined, I made it appear in comment in the code above in the function handleComplete.

Does anyone see what I am doing wrong? I don't see if the problem comes from my integration of vanillaJS in my React component, from my event management or from my way of creating the new listener element.

Thank you if you take the time to help me

CodePudding user response:

If you know the target is an input element you can use typescript casting

(e.target as HTMLInputElement).value
  • Related