내일배움캠프

230613 React contentEditable 속성을 가진 요소의 커서 초기화 문제

Neda 2023. 6. 13. 20:57

230613 React contentEditable 속성을 가진 요소의 커서 초기화 문제 해결하기

리액트를 이용한 TODO LIST를 만들던 중 할일을 보여주고 편집까지 되는 기능을 위해 contentEditable 속성을 가지는 요소를 만들어 값이 변경되면 useState를 통해 상태를 관리하려고 했다. 하지만 한글자를 친 이후부터는 커서가 항상 맨 앞으로 이동하는 문제가 발생했다.

문제가 되는 부분

문제가 되는 부분은 Todo 정보를 props로 받아서 useState에 초기값으로 지정하고

값을 사용하는 부분이다. 일반적으로 많이 사용하는 State 관리 방법이지만,

contentEditable에서는 커서 초기화 문제가 발생한다.

12345를 입력하면 1 -> 21 -> 321 -> 4321 -> 54321순으로 todoTitle값이 변경된다.

const TodoModal = ({ editTodo }) => {
  [todoTitle,setTodoTitle] = useState(editTodo.title);
  return(
    <h5 
      className='todoModal__title' 
      contentEditable='true' 
      suppressContentEditableWarning={true} 
      onInput={handleInputTitle}
    >
    {todoTitle}
    </h5>
  )
}

 

 

원인과 해결방법

useState

const [state, setState] = useState(initialState);

위와 같이 커서가 초기화되어 맨 앞으로 이동하고 안보이는 이유는 useState 값이 변경되어
리액트에서 리렌더링을 하기 때문이다. 한 글자 입력할 때마다 아주 빠르게 깜빡이는 것을 볼 수 있다.
요소가 리렌더링될 때 커서 위치가 초기화되는 것이다.

 

useRef

이 문제를 해결하기 위해서는 contentEditable 속성 내부 값이 변경되어도 리렌더링 하지 않도록 하면 되는데, React에서는 내장 Hook으로 useRef를 제공한다. useRef는 렌더링에 필요하지 않는 값을 참조할 수 있다. useRef는 값이 변경되어도 리렌더링 되지 않는다.

 

 

const TodoModal = ({ editTodo }) => {
  const todoTitle = useRef(editTodo.title);
  return(
    <h5 
      className='todoModal__title' 
      contentEditable='true' 
      suppressContentEditableWarning={true} 
      onInput={handleInputTitle}
    >
    {todoTitle.current}
    </h5>
  )
}

 

주의사항

Do not write or read ref.current during rendering. -React

리액트에서는 ref.current 값을 렌더링 중에 읽거나 쓰지 않도록 경고하고 있다. 
상태를 관리하는 것은 State를 사용하도록 권장하고 있다.

 


 

 

useRef – React

The library for web and native user interfaces

react.dev