Goldenbough
Goldenbough

Reputation: 93

How can I get focused element and change state in React component?

My intention is to update the 'isEditorFocused' state whenever the focused element changed, and if the div contains the focused element, deliver true into the Editor component.

However, the code does not work as my intention... It updates state only the first two times.

This is my Code. Actually not the exact code, but it is the core part of my question. If there is any typo, please ignore it. I checked it all in my real code file.

export default AddArticle = () => {

    const [isEditorFocused, setIsEditorFocused] = React.useState(false);

    const editorRef = React.useRef(null);

    React.useEffect(() => {
        if(editorRef.current !== null) {
            if(editorRef.current.contains(document.activeElement)
                setIsEditorFocused(true);
            else
                setIsEditorFocused(false);
        }
    }, [document.activeElement]}

    return (
        <div ref={editorRef} tabIndex="0">
            <Editor isEditorFocused={isEditorFocused}></Editor>
            <FileUploader {some props}/>
        </div>
    )
}

Upvotes: 0

Views: 5855

Answers (3)

user8924369
user8924369

Reputation:

try this way.

const AddArticle = () => {

  const [isEditorFocused, setIsEditorFocused] = React.useState(false);
  
  const handleBlur = (e) => {
    setIsEditorFocused(false)
  };

  handleFocus = (){
    const currentTarget = e.currentTarget;
    if (!currentTarget.contains(document.activeElement)) {
        setIsEditorFocused(true);
    }
  }

  return (
    <div onBlur={handleBlur} onFocus={handleFocus}>
      <Editor isEditorFocused={isEditorFocused}></Editor>
    </div>
  );
};

Upvotes: 0

Steve G
Steve G

Reputation: 13452

Not to completely change your code, but couldn't you just use onFocus and onBlur handlers?

For example:

const AddArticle = () => {
  const [isEditorFocused, setIsEditorFocused] = React.useState(false);

  return (
    <div
      onFocus={() => {
        setIsEditorFocused(true);
      }}
      onBlur={() => {
        setIsEditorFocused(false);
      }}
      tabIndex="0"
    >
      <Editor isEditorFocused={isEditorFocused}></Editor>
    </div>
  );
};

Working codepen

As T J mentions so eloquently, your issue is with document.activeElement

Note regarding React's current support for onFocus vs onFocusIn:

React uses onFocus and onBlur instead of onFocusIn and onFocusOut. All React events are normalized to bubble, so onFocusIn and onFocusOut are not needed/supported by React.

Source: React Github

Upvotes: 1

T J
T J

Reputation: 43166

The main problem is this: [document.activeElement].
The useEffect dependency array only works with React state, and document.activeElement is not React state.

You can try using a focusin event listener on your <div>, if it receives the event it means itself or something inside it got focus, since focusin event bubbles as long as nothing inside is explicitly preventing propagation of this event.

Upvotes: 0

Related Questions